| 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 "content/browser/renderer_host/media/video_capture_controller.h" | 5 #include "content/browser/renderer_host/media/video_capture_controller.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 ~ControllerClient() {} | 42 ~ControllerClient() {} |
| 43 | 43 |
| 44 // ID used for identifying this object. | 44 // ID used for identifying this object. |
| 45 VideoCaptureControllerID controller_id; | 45 VideoCaptureControllerID controller_id; |
| 46 VideoCaptureControllerEventHandler* event_handler; | 46 VideoCaptureControllerEventHandler* event_handler; |
| 47 | 47 |
| 48 // Handle to the render process that will receive the capture buffers. | 48 // Handle to the render process that will receive the capture buffers. |
| 49 base::ProcessHandle render_process_handle; | 49 base::ProcessHandle render_process_handle; |
| 50 media::VideoCaptureParams parameters; | 50 media::VideoCaptureParams parameters; |
| 51 | 51 |
| 52 // Buffers used by this client. | 52 // Buffers that are currently known to this client. |
| 53 std::set<int> buffers; | 53 std::set<int> known_buffers; |
| 54 |
| 55 // Buffers currently held by this client. |
| 56 std::set<int> active_buffers; |
| 54 | 57 |
| 55 // State of capture session, controlled by VideoCaptureManager directly. This | 58 // State of capture session, controlled by VideoCaptureManager directly. This |
| 56 // transitions to true as soon as StopSession() occurs, at which point the | 59 // transitions to true as soon as StopSession() occurs, at which point the |
| 57 // client is sent an OnEnded() event. However, because the client retains a | 60 // client is sent an OnEnded() event. However, because the client retains a |
| 58 // VideoCaptureController* pointer, its ControllerClient entry lives on until | 61 // VideoCaptureController* pointer, its ControllerClient entry lives on until |
| 59 // it unregisters itself via RemoveClient(), which may happen asynchronously. | 62 // it unregisters itself via RemoveClient(), which may happen asynchronously. |
| 60 // | 63 // |
| 61 // TODO(nick): If we changed the semantics of VideoCaptureHost so that | 64 // TODO(nick): If we changed the semantics of VideoCaptureHost so that |
| 62 // OnEnded() events were processed synchronously (with the RemoveClient() done | 65 // OnEnded() events were processed synchronously (with the RemoveClient() done |
| 63 // implicitly), we could avoid tracking this state here in the Controller, and | 66 // implicitly), we could avoid tracking this state here in the Controller, and |
| 64 // simplify the code in both places. | 67 // simplify the code in both places. |
| 65 bool session_closed; | 68 bool session_closed; |
| 66 }; | 69 }; |
| 67 | 70 |
| 68 // Receives events from the VideoCaptureDevice and posts them to a | 71 // Receives events from the VideoCaptureDevice and posts them to a |
| 69 // VideoCaptureController on the IO thread. An instance of this class may safely | 72 // VideoCaptureController on the IO thread. An instance of this class may safely |
| 70 // outlive its target VideoCaptureController. | 73 // outlive its target VideoCaptureController. |
| 71 // | 74 // |
| 72 // Methods of this class may be called from any thread, and in practice will | 75 // Methods of this class may be called from any thread, and in practice will |
| 73 // often be called on some auxiliary thread depending on the platform and the | 76 // often be called on some auxiliary thread depending on the platform and the |
| 74 // device type; including, for example, the DirectShow thread on Windows, the | 77 // device type; including, for example, the DirectShow thread on Windows, the |
| 75 // v4l2_thread on Linux, and the UI thread for tab capture. | 78 // v4l2_thread on Linux, and the UI thread for tab capture. |
| 76 class VideoCaptureController::VideoCaptureDeviceClient | 79 class VideoCaptureController::VideoCaptureDeviceClient |
| 77 : public media::VideoCaptureDevice::Client { | 80 : public media::VideoCaptureDevice::Client { |
| 78 public: | 81 public: |
| 79 explicit VideoCaptureDeviceClient( | 82 explicit VideoCaptureDeviceClient( |
| 80 const base::WeakPtr<VideoCaptureController>& controller); | 83 const base::WeakPtr<VideoCaptureController>& controller, |
| 84 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool); |
| 81 virtual ~VideoCaptureDeviceClient(); | 85 virtual ~VideoCaptureDeviceClient(); |
| 82 | 86 |
| 83 // VideoCaptureDevice::Client implementation. | 87 // VideoCaptureDevice::Client implementation. |
| 84 virtual scoped_refptr<media::VideoFrame> ReserveOutputBuffer() OVERRIDE; | 88 virtual scoped_refptr<media::VideoFrame> ReserveOutputBuffer( |
| 89 const gfx::Size& size) OVERRIDE; |
| 85 virtual void OnIncomingCapturedFrame(const uint8* data, | 90 virtual void OnIncomingCapturedFrame(const uint8* data, |
| 86 int length, | 91 int length, |
| 87 base::Time timestamp, | 92 base::Time timestamp, |
| 88 int rotation, | 93 int rotation, |
| 89 bool flip_vert, | 94 bool flip_vert, |
| 90 bool flip_horiz) OVERRIDE; | 95 bool flip_horiz) OVERRIDE; |
| 91 virtual void OnIncomingCapturedVideoFrame( | 96 virtual void OnIncomingCapturedVideoFrame( |
| 92 const scoped_refptr<media::VideoFrame>& frame, | 97 const scoped_refptr<media::VideoFrame>& frame, |
| 93 base::Time timestamp) OVERRIDE; | 98 base::Time timestamp) OVERRIDE; |
| 94 virtual void OnError() OVERRIDE; | 99 virtual void OnError() OVERRIDE; |
| 95 virtual void OnFrameInfo( | 100 virtual void OnFrameInfo( |
| 96 const media::VideoCaptureCapability& info) OVERRIDE; | 101 const media::VideoCaptureCapability& info) OVERRIDE; |
| 97 virtual void OnFrameInfoChanged( | 102 virtual void OnFrameInfoChanged( |
| 98 const media::VideoCaptureCapability& info) OVERRIDE; | 103 const media::VideoCaptureCapability& info) OVERRIDE; |
| 99 | 104 |
| 100 private: | 105 private: |
| 106 scoped_refptr<media::VideoFrame> DoReserveI420VideoFrame( |
| 107 const gfx::Size& size, |
| 108 int rotation); |
| 109 |
| 101 // The controller to which we post events. | 110 // The controller to which we post events. |
| 102 const base::WeakPtr<VideoCaptureController> controller_; | 111 const base::WeakPtr<VideoCaptureController> controller_; |
| 103 | 112 |
| 104 // The pool of shared-memory buffers used for capturing. | 113 // The pool of shared-memory buffers used for capturing. |
| 105 scoped_refptr<VideoCaptureBufferPool> buffer_pool_; | 114 const scoped_refptr<VideoCaptureBufferPool> buffer_pool_; |
| 106 | 115 |
| 107 // Chopped pixels in width/height in case video capture device has odd | 116 // Chopped pixels in width/height in case video capture device has odd |
| 108 // numbers for width/height. | 117 // numbers for width/height. |
| 109 int chopped_width_; | 118 int chopped_width_; |
| 110 int chopped_height_; | 119 int chopped_height_; |
| 111 | 120 |
| 112 // Tracks the current frame format. | 121 // Tracks the current frame format. |
| 113 media::VideoCaptureCapability frame_info_; | 122 media::VideoCaptureCapability frame_info_; |
| 114 }; | 123 }; |
| 115 | 124 |
| 116 VideoCaptureController::VideoCaptureController() | 125 VideoCaptureController::VideoCaptureController() |
| 117 : state_(VIDEO_CAPTURE_STATE_STARTED), | 126 : buffer_pool_(new VideoCaptureBufferPool(kNoOfBuffers)), |
| 127 state_(VIDEO_CAPTURE_STATE_STARTED), |
| 118 weak_ptr_factory_(this) { | 128 weak_ptr_factory_(this) { |
| 119 memset(¤t_params_, 0, sizeof(current_params_)); | |
| 120 } | 129 } |
| 121 | 130 |
| 122 VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient( | 131 VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient( |
| 123 const base::WeakPtr<VideoCaptureController>& controller) | 132 const base::WeakPtr<VideoCaptureController>& controller, |
| 133 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool) |
| 124 : controller_(controller), | 134 : controller_(controller), |
| 135 buffer_pool_(buffer_pool), |
| 125 chopped_width_(0), | 136 chopped_width_(0), |
| 126 chopped_height_(0) {} | 137 chopped_height_(0) {} |
| 127 | 138 |
| 128 VideoCaptureController::VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {} | 139 VideoCaptureController::VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {} |
| 129 | 140 |
| 130 base::WeakPtr<VideoCaptureController> VideoCaptureController::GetWeakPtr() { | 141 base::WeakPtr<VideoCaptureController> VideoCaptureController::GetWeakPtr() { |
| 131 return weak_ptr_factory_.GetWeakPtr(); | 142 return weak_ptr_factory_.GetWeakPtr(); |
| 132 } | 143 } |
| 133 | 144 |
| 134 scoped_ptr<media::VideoCaptureDevice::Client> | 145 scoped_ptr<media::VideoCaptureDevice::Client> |
| 135 VideoCaptureController::NewDeviceClient() { | 146 VideoCaptureController::NewDeviceClient() { |
| 136 scoped_ptr<media::VideoCaptureDevice::Client> result( | 147 scoped_ptr<media::VideoCaptureDevice::Client> result( |
| 137 new VideoCaptureDeviceClient(this->GetWeakPtr())); | 148 new VideoCaptureDeviceClient(this->GetWeakPtr(), buffer_pool_)); |
| 138 return result.Pass(); | 149 return result.Pass(); |
| 139 } | 150 } |
| 140 | 151 |
| 141 void VideoCaptureController::AddClient( | 152 void VideoCaptureController::AddClient( |
| 142 const VideoCaptureControllerID& id, | 153 const VideoCaptureControllerID& id, |
| 143 VideoCaptureControllerEventHandler* event_handler, | 154 VideoCaptureControllerEventHandler* event_handler, |
| 144 base::ProcessHandle render_process, | 155 base::ProcessHandle render_process, |
| 145 const media::VideoCaptureParams& params) { | 156 const media::VideoCaptureParams& params) { |
| 146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 147 DVLOG(1) << "VideoCaptureController::AddClient, id " << id.device_id | 158 DVLOG(1) << "VideoCaptureController::AddClient, id " << id.device_id |
| 148 << ", (" << params.width | 159 << ", (" << params.requested_format.width |
| 149 << ", " << params.height | 160 << ", " << params.requested_format.height |
| 150 << ", " << params.frame_rate | 161 << ", " << params.requested_format.frame_rate |
| 151 << ", " << params.session_id | 162 << ", " << params.session_id |
| 152 << ")"; | 163 << ")"; |
| 153 | 164 |
| 154 // Signal error in case device is already in error state. | 165 // Signal error in case device is already in error state. |
| 155 if (state_ == VIDEO_CAPTURE_STATE_ERROR) { | 166 if (state_ == VIDEO_CAPTURE_STATE_ERROR) { |
| 156 event_handler->OnError(id); | 167 event_handler->OnError(id); |
| 157 return; | 168 return; |
| 158 } | 169 } |
| 159 | 170 |
| 160 // Do nothing if this client has called AddClient before. | 171 // Do nothing if this client has called AddClient before. |
| 161 if (FindClient(id, event_handler, controller_clients_)) | 172 if (FindClient(id, event_handler, controller_clients_)) |
| 162 return; | 173 return; |
| 163 | 174 |
| 164 ControllerClient* client = new ControllerClient(id, event_handler, | 175 ControllerClient* client = new ControllerClient(id, event_handler, |
| 165 render_process, params); | 176 render_process, params); |
| 166 // If we already have gotten frame_info from the device, repeat it to the new | 177 // If we already have gotten frame_info from the device, repeat it to the new |
| 167 // client. | 178 // client. |
| 168 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 179 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
| 169 if (frame_info_.IsValid()) { | |
| 170 SendFrameInfoAndBuffers(client); | |
| 171 } | |
| 172 controller_clients_.push_back(client); | 180 controller_clients_.push_back(client); |
| 173 return; | 181 return; |
| 174 } | 182 } |
| 175 } | 183 } |
| 176 | 184 |
| 177 int VideoCaptureController::RemoveClient( | 185 int VideoCaptureController::RemoveClient( |
| 178 const VideoCaptureControllerID& id, | 186 const VideoCaptureControllerID& id, |
| 179 VideoCaptureControllerEventHandler* event_handler) { | 187 VideoCaptureControllerEventHandler* event_handler) { |
| 180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 181 DVLOG(1) << "VideoCaptureController::RemoveClient, id " << id.device_id; | 189 DVLOG(1) << "VideoCaptureController::RemoveClient, id " << id.device_id; |
| 182 | 190 |
| 183 ControllerClient* client = FindClient(id, event_handler, controller_clients_); | 191 ControllerClient* client = FindClient(id, event_handler, controller_clients_); |
| 184 if (!client) | 192 if (!client) |
| 185 return kInvalidMediaCaptureSessionId; | 193 return kInvalidMediaCaptureSessionId; |
| 186 | 194 |
| 187 // Take back all buffers held by the |client|. | 195 // Take back all buffers held by the |client|. |
| 188 if (buffer_pool_.get()) { | 196 for (std::set<int>::iterator buffer_it = client->active_buffers.begin(); |
| 189 for (std::set<int>::iterator buffer_it = client->buffers.begin(); | 197 buffer_it != client->active_buffers.end(); |
| 190 buffer_it != client->buffers.end(); | 198 ++buffer_it) { |
| 191 ++buffer_it) { | 199 int buffer_id = *buffer_it; |
| 192 int buffer_id = *buffer_it; | 200 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); |
| 193 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); | |
| 194 } | |
| 195 } | 201 } |
| 196 client->buffers.clear(); | 202 client->active_buffers.clear(); |
| 197 | 203 |
| 198 int session_id = client->parameters.session_id; | 204 int session_id = client->parameters.session_id; |
| 199 controller_clients_.remove(client); | 205 controller_clients_.remove(client); |
| 200 delete client; | 206 delete client; |
| 201 | 207 |
| 202 return session_id; | 208 return session_id; |
| 203 } | 209 } |
| 204 | 210 |
| 205 void VideoCaptureController::StopSession(int session_id) { | 211 void VideoCaptureController::StopSession(int session_id) { |
| 206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 217 void VideoCaptureController::ReturnBuffer( | 223 void VideoCaptureController::ReturnBuffer( |
| 218 const VideoCaptureControllerID& id, | 224 const VideoCaptureControllerID& id, |
| 219 VideoCaptureControllerEventHandler* event_handler, | 225 VideoCaptureControllerEventHandler* event_handler, |
| 220 int buffer_id) { | 226 int buffer_id) { |
| 221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 222 | 228 |
| 223 ControllerClient* client = FindClient(id, event_handler, controller_clients_); | 229 ControllerClient* client = FindClient(id, event_handler, controller_clients_); |
| 224 | 230 |
| 225 // If this buffer is not held by this client, or this client doesn't exist | 231 // If this buffer is not held by this client, or this client doesn't exist |
| 226 // in controller, do nothing. | 232 // in controller, do nothing. |
| 227 if (!client || | 233 if (!client || !client->active_buffers.erase(buffer_id)) { |
| 228 client->buffers.find(buffer_id) == client->buffers.end()) { | |
| 229 NOTREACHED(); | 234 NOTREACHED(); |
| 230 return; | 235 return; |
| 231 } | 236 } |
| 232 | 237 |
| 233 client->buffers.erase(buffer_id); | |
| 234 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); | 238 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); |
| 235 } | 239 } |
| 236 | 240 |
| 237 scoped_refptr<media::VideoFrame> | 241 scoped_refptr<media::VideoFrame> |
| 238 VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer() { | 242 VideoCaptureController::VideoCaptureDeviceClient::ReserveOutputBuffer( |
| 239 return buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width, | 243 const gfx::Size& size) { |
| 240 frame_info_.height), | 244 return DoReserveI420VideoFrame(size, 0); |
| 241 0); | |
| 242 } | 245 } |
| 243 | 246 |
| 244 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame( | 247 void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedFrame( |
| 245 const uint8* data, | 248 const uint8* data, |
| 246 int length, | 249 int length, |
| 247 base::Time timestamp, | 250 base::Time timestamp, |
| 248 int rotation, | 251 int rotation, |
| 249 bool flip_vert, | 252 bool flip_vert, |
| 250 bool flip_horiz) { | 253 bool flip_horiz) { |
| 251 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); | 254 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); |
| 252 | 255 |
| 253 if (!buffer_pool_.get()) | 256 if (!frame_info_.IsValid()) |
| 254 return; | 257 return; |
| 255 scoped_refptr<media::VideoFrame> dst = buffer_pool_->ReserveI420VideoFrame( | 258 |
| 259 scoped_refptr<media::VideoFrame> dst = DoReserveI420VideoFrame( |
| 256 gfx::Size(frame_info_.width, frame_info_.height), rotation); | 260 gfx::Size(frame_info_.width, frame_info_.height), rotation); |
| 257 | 261 |
| 258 if (!dst.get()) | 262 if (!dst.get()) |
| 259 return; | 263 return; |
| 260 #if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) | 264 #if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) |
| 261 | 265 |
| 262 uint8* yplane = dst->data(media::VideoFrame::kYPlane); | 266 uint8* yplane = dst->data(media::VideoFrame::kYPlane); |
| 263 uint8* uplane = dst->data(media::VideoFrame::kUPlane); | 267 uint8* uplane = dst->data(media::VideoFrame::kUPlane); |
| 264 uint8* vplane = dst->data(media::VideoFrame::kVPlane); | 268 uint8* vplane = dst->data(media::VideoFrame::kVPlane); |
| 265 int yplane_stride = frame_info_.width; | 269 int yplane_stride = frame_info_.width; |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 380 // not used in those builds either. Whenever libyuv is added in that build, | 384 // not used in those builds either. Whenever libyuv is added in that build, |
| 381 // address all these #ifdef parts, see http://crbug.com/299611 . | 385 // address all these #ifdef parts, see http://crbug.com/299611 . |
| 382 NOTREACHED(); | 386 NOTREACHED(); |
| 383 #endif // if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) | 387 #endif // if !defined(AVOID_LIBYUV_FOR_ANDROID_WEBVIEW) |
| 384 BrowserThread::PostTask( | 388 BrowserThread::PostTask( |
| 385 BrowserThread::IO, | 389 BrowserThread::IO, |
| 386 FROM_HERE, | 390 FROM_HERE, |
| 387 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 391 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, |
| 388 controller_, | 392 controller_, |
| 389 dst, | 393 dst, |
| 394 frame_info_.frame_rate, |
| 390 timestamp)); | 395 timestamp)); |
| 391 } | 396 } |
| 392 | 397 |
| 393 void | 398 void |
| 394 VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame( | 399 VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame( |
| 395 const scoped_refptr<media::VideoFrame>& frame, | 400 const scoped_refptr<media::VideoFrame>& frame, |
| 396 base::Time timestamp) { | 401 base::Time timestamp) { |
| 397 if (!buffer_pool_) | |
| 398 return; | |
| 399 | 402 |
| 400 // If this is a frame that belongs to the buffer pool, we can forward it | 403 // If this is a frame that belongs to the buffer pool, we can forward it |
| 401 // directly to the IO thread and be done. | 404 // directly to the IO thread and be done. |
| 402 if (buffer_pool_->RecognizeReservedBuffer( | 405 if (buffer_pool_->RecognizeReservedBuffer( |
| 403 frame->shared_memory_handle()) >= 0) { | 406 frame->shared_memory_handle()) >= 0) { |
| 404 BrowserThread::PostTask(BrowserThread::IO, | 407 BrowserThread::PostTask(BrowserThread::IO, |
| 405 FROM_HERE, | 408 FROM_HERE, |
| 406 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 409 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, |
| 407 controller_, frame, timestamp)); | 410 controller_, frame, frame_info_.frame_rate, timestamp)); |
| 408 return; | 411 return; |
| 409 } | 412 } |
| 410 | 413 |
| 411 // Otherwise, this is a frame that belongs to the caller, and we must copy | 414 NOTREACHED() << "Frames should always belong to the buffer pool."; |
| 412 // it to a frame from the buffer pool. | |
| 413 scoped_refptr<media::VideoFrame> target = | |
| 414 buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width, | |
| 415 frame_info_.height), | |
| 416 0); | |
| 417 | |
| 418 if (!target.get()) | |
| 419 return; | |
| 420 | |
| 421 // Validate the inputs. | |
| 422 if (frame->coded_size() != target->coded_size()) | |
| 423 return; // Only exact copies are supported. | |
| 424 if (!(frame->format() == media::VideoFrame::I420 || | |
| 425 frame->format() == media::VideoFrame::YV12 || | |
| 426 frame->format() == media::VideoFrame::RGB32)) { | |
| 427 NOTREACHED() << "Unsupported format passed to OnIncomingCapturedVideoFrame"; | |
| 428 return; | |
| 429 } | |
| 430 | |
| 431 const int kYPlane = media::VideoFrame::kYPlane; | |
| 432 const int kUPlane = media::VideoFrame::kUPlane; | |
| 433 const int kVPlane = media::VideoFrame::kVPlane; | |
| 434 const int kAPlane = media::VideoFrame::kAPlane; | |
| 435 const int kRGBPlane = media::VideoFrame::kRGBPlane; | |
| 436 | |
| 437 // Do color conversion from the camera format to I420. | |
| 438 switch (frame->format()) { | |
| 439 #if defined(GOOGLE_TV) | |
| 440 case media::VideoFrame::HOLE: | |
| 441 // Fall-through to NOTREACHED() block. | |
| 442 #endif | |
| 443 case media::VideoFrame::INVALID: | |
| 444 case media::VideoFrame::YV16: | |
| 445 case media::VideoFrame::EMPTY: | |
| 446 case media::VideoFrame::NATIVE_TEXTURE: { | |
| 447 NOTREACHED(); | |
| 448 break; | |
| 449 } | |
| 450 case media::VideoFrame::I420: | |
| 451 case media::VideoFrame::YV12: { | |
| 452 DCHECK(!chopped_width_ && !chopped_height_); | |
| 453 media::CopyYPlane(frame->data(kYPlane), | |
| 454 frame->stride(kYPlane), | |
| 455 frame->rows(kYPlane), | |
| 456 target.get()); | |
| 457 media::CopyUPlane(frame->data(kUPlane), | |
| 458 frame->stride(kUPlane), | |
| 459 frame->rows(kUPlane), | |
| 460 target.get()); | |
| 461 media::CopyVPlane(frame->data(kVPlane), | |
| 462 frame->stride(kVPlane), | |
| 463 frame->rows(kVPlane), | |
| 464 target.get()); | |
| 465 break; | |
| 466 } | |
| 467 case media::VideoFrame::YV12A: { | |
| 468 DCHECK(!chopped_width_ && !chopped_height_); | |
| 469 media::CopyYPlane(frame->data(kYPlane), | |
| 470 frame->stride(kYPlane), | |
| 471 frame->rows(kYPlane), | |
| 472 target.get()); | |
| 473 media::CopyUPlane(frame->data(kUPlane), | |
| 474 frame->stride(kUPlane), | |
| 475 frame->rows(kUPlane), | |
| 476 target.get()); | |
| 477 media::CopyVPlane(frame->data(kVPlane), | |
| 478 frame->stride(kVPlane), | |
| 479 frame->rows(kVPlane), | |
| 480 target.get()); | |
| 481 media::CopyAPlane(frame->data(kAPlane), | |
| 482 frame->stride(kAPlane), | |
| 483 frame->rows(kAPlane), | |
| 484 target.get()); | |
| 485 break; | |
| 486 } | |
| 487 case media::VideoFrame::RGB32: { | |
| 488 media::ConvertRGB32ToYUV(frame->data(kRGBPlane), | |
| 489 target->data(kYPlane), | |
| 490 target->data(kUPlane), | |
| 491 target->data(kVPlane), | |
| 492 target->coded_size().width(), | |
| 493 target->coded_size().height(), | |
| 494 frame->stride(kRGBPlane), | |
| 495 target->stride(kYPlane), | |
| 496 target->stride(kUPlane)); | |
| 497 break; | |
| 498 } | |
| 499 } | |
| 500 | |
| 501 BrowserThread::PostTask(BrowserThread::IO, | |
| 502 FROM_HERE, | |
| 503 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | |
| 504 controller_, target, timestamp)); | |
| 505 } | 415 } |
| 506 | 416 |
| 507 void VideoCaptureController::VideoCaptureDeviceClient::OnError() { | 417 void VideoCaptureController::VideoCaptureDeviceClient::OnError() { |
| 508 BrowserThread::PostTask(BrowserThread::IO, | 418 BrowserThread::PostTask(BrowserThread::IO, |
| 509 FROM_HERE, | 419 FROM_HERE, |
| 510 base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_)); | 420 base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_)); |
| 511 } | 421 } |
| 512 | 422 |
| 513 void VideoCaptureController::VideoCaptureDeviceClient::OnFrameInfo( | 423 void VideoCaptureController::VideoCaptureDeviceClient::OnFrameInfo( |
| 514 const media::VideoCaptureCapability& info) { | 424 const media::VideoCaptureCapability& info) { |
| 515 frame_info_ = info; | 425 frame_info_ = info; |
| 516 // Handle cases when |info| has odd numbers for width/height. | 426 // Handle cases when |info| has odd numbers for width/height. |
| 517 if (info.width & 1) { | 427 if (info.width & 1) { |
| 518 --frame_info_.width; | 428 --frame_info_.width; |
| 519 chopped_width_ = 1; | 429 chopped_width_ = 1; |
| 520 } else { | 430 } else { |
| 521 chopped_width_ = 0; | 431 chopped_width_ = 0; |
| 522 } | 432 } |
| 523 if (info.height & 1) { | 433 if (info.height & 1) { |
| 524 --frame_info_.height; | 434 --frame_info_.height; |
| 525 chopped_height_ = 1; | 435 chopped_height_ = 1; |
| 526 } else { | 436 } else { |
| 527 chopped_height_ = 0; | 437 chopped_height_ = 0; |
| 528 } | 438 } |
| 529 | |
| 530 DCHECK(!buffer_pool_.get()); | |
| 531 | |
| 532 // TODO(nick): Give BufferPool the same lifetime as the controller, have it | |
| 533 // support frame size changes, and stop checking it for NULL everywhere. | |
| 534 // http://crbug.com/266082 | |
| 535 buffer_pool_ = new VideoCaptureBufferPool( | |
| 536 media::VideoFrame::AllocationSize( | |
| 537 media::VideoFrame::I420, | |
| 538 gfx::Size(frame_info_.width, frame_info_.height)), | |
| 539 kNoOfBuffers); | |
| 540 | |
| 541 // Check whether all buffers were created successfully. | |
| 542 if (!buffer_pool_->Allocate()) { | |
| 543 // Transition to the error state. | |
| 544 buffer_pool_ = NULL; | |
| 545 OnError(); | |
| 546 return; | |
| 547 } | |
| 548 | |
| 549 BrowserThread::PostTask(BrowserThread::IO, | |
| 550 FROM_HERE, | |
| 551 base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread, controller_, | |
| 552 frame_info_, buffer_pool_)); | |
| 553 } | 439 } |
| 554 | 440 |
| 555 void VideoCaptureController::VideoCaptureDeviceClient::OnFrameInfoChanged( | 441 void VideoCaptureController::VideoCaptureDeviceClient::OnFrameInfoChanged( |
| 556 const media::VideoCaptureCapability& info) { | 442 const media::VideoCaptureCapability& info) { |
| 557 BrowserThread::PostTask(BrowserThread::IO, | 443 OnFrameInfo(info); |
| 558 FROM_HERE, | 444 } |
| 559 base::Bind(&VideoCaptureController::DoFrameInfoChangedOnIOThread, | 445 |
| 560 controller_, info)); | 446 scoped_refptr<media::VideoFrame> |
| 447 VideoCaptureController::VideoCaptureDeviceClient::DoReserveI420VideoFrame( |
| 448 const gfx::Size& size, |
| 449 int rotation) { |
| 450 int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId; |
| 451 scoped_refptr<media::VideoFrame> frame = |
| 452 buffer_pool_->ReserveI420VideoFrame(size, rotation, &buffer_id_to_drop); |
| 453 if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) { |
| 454 BrowserThread::PostTask(BrowserThread::IO, |
| 455 FROM_HERE, |
| 456 base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread, |
| 457 controller_, buffer_id_to_drop)); |
| 458 } |
| 459 return frame; |
| 561 } | 460 } |
| 562 | 461 |
| 563 VideoCaptureController::~VideoCaptureController() { | 462 VideoCaptureController::~VideoCaptureController() { |
| 564 buffer_pool_ = NULL; // Release all buffers. | |
| 565 STLDeleteContainerPointers(controller_clients_.begin(), | 463 STLDeleteContainerPointers(controller_clients_.begin(), |
| 566 controller_clients_.end()); | 464 controller_clients_.end()); |
| 567 } | 465 } |
| 568 | 466 |
| 569 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( | 467 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( |
| 570 const scoped_refptr<media::VideoFrame>& reserved_frame, | 468 const scoped_refptr<media::VideoFrame>& reserved_frame, |
| 469 int frame_rate, |
| 571 base::Time timestamp) { | 470 base::Time timestamp) { |
| 572 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 471 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 573 | 472 |
| 574 if (!buffer_pool_.get()) | |
| 575 return; | |
| 576 | |
| 577 int buffer_id = buffer_pool_->RecognizeReservedBuffer( | 473 int buffer_id = buffer_pool_->RecognizeReservedBuffer( |
| 578 reserved_frame->shared_memory_handle()); | 474 reserved_frame->shared_memory_handle()); |
| 579 if (buffer_id < 0) { | 475 if (buffer_id < 0) { |
| 580 NOTREACHED(); | 476 NOTREACHED(); |
| 581 return; | 477 return; |
| 582 } | 478 } |
| 583 | 479 |
| 480 media::VideoCaptureFormat frame_format( |
| 481 reserved_frame->coded_size().width(), |
| 482 reserved_frame->coded_size().height(), |
| 483 frame_rate, |
| 484 media::VariableResolutionVideoCaptureDevice); |
| 485 |
| 584 int count = 0; | 486 int count = 0; |
| 585 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 487 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
| 586 for (ControllerClients::iterator client_it = controller_clients_.begin(); | 488 for (ControllerClients::iterator client_it = controller_clients_.begin(); |
| 587 client_it != controller_clients_.end(); ++client_it) { | 489 client_it != controller_clients_.end(); ++client_it) { |
| 588 if ((*client_it)->session_closed) | 490 ControllerClient* client = *client_it; |
| 491 if (client->session_closed) |
| 589 continue; | 492 continue; |
| 590 | 493 |
| 591 (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id, | 494 bool is_new_buffer = client->known_buffers.insert(buffer_id).second; |
| 592 buffer_id, timestamp); | 495 if (is_new_buffer) { |
| 593 (*client_it)->buffers.insert(buffer_id); | 496 // On the first use of a buffer on a client, share the memory handle. |
| 497 size_t memory_size = 0; |
| 498 base::SharedMemoryHandle remote_handle = buffer_pool_->ShareToProcess( |
| 499 buffer_id, client->render_process_handle, &memory_size); |
| 500 client->event_handler->OnBufferCreated(client->controller_id, |
| 501 remote_handle, |
| 502 memory_size, |
| 503 buffer_id); |
| 504 } |
| 505 |
| 506 client->event_handler->OnBufferReady(client->controller_id, |
| 507 buffer_id, timestamp, |
| 508 frame_format); |
| 509 bool inserted = client->active_buffers.insert(buffer_id).second; |
| 510 DCHECK(inserted) << "Unexpected duplicate buffer: " << buffer_id; |
| 594 count++; | 511 count++; |
| 595 } | 512 } |
| 596 } | 513 } |
| 597 | 514 |
| 598 buffer_pool_->HoldForConsumers(buffer_id, count); | 515 buffer_pool_->HoldForConsumers(buffer_id, count); |
| 599 } | 516 } |
| 600 | 517 |
| 601 void VideoCaptureController::DoFrameInfoOnIOThread( | |
| 602 const media::VideoCaptureCapability& frame_info, | |
| 603 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool) { | |
| 604 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 605 DCHECK(!buffer_pool_.get()) << "Frame info should happen only once."; | |
| 606 | |
| 607 // Allocate memory only when device has been started. | |
| 608 if (state_ != VIDEO_CAPTURE_STATE_STARTED) | |
| 609 return; | |
| 610 | |
| 611 frame_info_ = frame_info; | |
| 612 buffer_pool_ = buffer_pool; | |
| 613 | |
| 614 for (ControllerClients::iterator client_it = controller_clients_.begin(); | |
| 615 client_it != controller_clients_.end(); ++client_it) { | |
| 616 if ((*client_it)->session_closed) | |
| 617 continue; | |
| 618 | |
| 619 SendFrameInfoAndBuffers(*client_it); | |
| 620 } | |
| 621 } | |
| 622 | |
| 623 void VideoCaptureController::DoFrameInfoChangedOnIOThread( | |
| 624 const media::VideoCaptureCapability& info) { | |
| 625 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 626 // TODO(mcasas): Here we should reallocate the VideoCaptureBufferPool, if | |
| 627 // needed, to support the new video capture format. See crbug.com/266082. | |
| 628 for (ControllerClients::iterator client_it = controller_clients_.begin(); | |
| 629 client_it != controller_clients_.end(); ++client_it) { | |
| 630 if ((*client_it)->session_closed) | |
| 631 continue; | |
| 632 | |
| 633 (*client_it)->event_handler->OnFrameInfoChanged( | |
| 634 (*client_it)->controller_id, | |
| 635 info.width, | |
| 636 info.height, | |
| 637 info.frame_rate); | |
| 638 } | |
| 639 } | |
| 640 | |
| 641 void VideoCaptureController::DoErrorOnIOThread() { | 518 void VideoCaptureController::DoErrorOnIOThread() { |
| 642 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 519 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 643 state_ = VIDEO_CAPTURE_STATE_ERROR; | 520 state_ = VIDEO_CAPTURE_STATE_ERROR; |
| 644 ControllerClients::iterator client_it; | 521 |
| 645 for (client_it = controller_clients_.begin(); | 522 for (ControllerClients::iterator client_it = controller_clients_.begin(); |
| 646 client_it != controller_clients_.end(); ++client_it) { | 523 client_it != controller_clients_.end(); ++client_it) { |
| 647 if ((*client_it)->session_closed) | 524 ControllerClient* client = *client_it; |
| 648 continue; | 525 if (client->session_closed) |
| 526 continue; |
| 649 | 527 |
| 650 (*client_it)->event_handler->OnError((*client_it)->controller_id); | 528 client->event_handler->OnError(client->controller_id); |
| 651 } | 529 } |
| 652 } | 530 } |
| 653 | 531 |
| 654 void VideoCaptureController::SendFrameInfoAndBuffers(ControllerClient* client) { | 532 void VideoCaptureController::DoBufferDestroyedOnIOThread( |
| 533 int buffer_id_to_drop) { |
| 655 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 534 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 656 DCHECK(frame_info_.IsValid()); | |
| 657 client->event_handler->OnFrameInfo(client->controller_id, | |
| 658 frame_info_); | |
| 659 for (int buffer_id = 0; buffer_id < buffer_pool_->count(); ++buffer_id) { | |
| 660 base::SharedMemoryHandle remote_handle = | |
| 661 buffer_pool_->ShareToProcess(buffer_id, client->render_process_handle); | |
| 662 | 535 |
| 663 client->event_handler->OnBufferCreated(client->controller_id, | 536 for (ControllerClients::iterator client_it = controller_clients_.begin(); |
| 664 remote_handle, | 537 client_it != controller_clients_.end(); ++client_it) { |
| 665 buffer_pool_->GetMemorySize(), | 538 ControllerClient* client = *client_it; |
| 666 buffer_id); | 539 if (client->session_closed) |
| 540 continue; |
| 541 |
| 542 if (client->known_buffers.erase(buffer_id_to_drop)) { |
| 543 client->event_handler->OnBufferDestroyed(client->controller_id, |
| 544 buffer_id_to_drop); |
| 545 } |
| 667 } | 546 } |
| 668 } | 547 } |
| 669 | 548 |
| 670 VideoCaptureController::ControllerClient* | 549 VideoCaptureController::ControllerClient* |
| 671 VideoCaptureController::FindClient( | 550 VideoCaptureController::FindClient( |
| 672 const VideoCaptureControllerID& id, | 551 const VideoCaptureControllerID& id, |
| 673 VideoCaptureControllerEventHandler* handler, | 552 VideoCaptureControllerEventHandler* handler, |
| 674 const ControllerClients& clients) { | 553 const ControllerClients& clients) { |
| 675 for (ControllerClients::const_iterator client_it = clients.begin(); | 554 for (ControllerClients::const_iterator client_it = clients.begin(); |
| 676 client_it != clients.end(); ++client_it) { | 555 client_it != clients.end(); ++client_it) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 694 } | 573 } |
| 695 return NULL; | 574 return NULL; |
| 696 } | 575 } |
| 697 | 576 |
| 698 int VideoCaptureController::GetClientCount() { | 577 int VideoCaptureController::GetClientCount() { |
| 699 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 578 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 700 return controller_clients_.size(); | 579 return controller_clients_.size(); |
| 701 } | 580 } |
| 702 | 581 |
| 703 } // namespace content | 582 } // namespace content |
| OLD | NEW |