| 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 // Notes about usage of this object by VideoCaptureImplManager. | 5 // Notes about usage of this object by VideoCaptureImplManager. |
| 6 // | 6 // |
| 7 // VideoCaptureImplManager access this object by using a Unretained() | 7 // VideoCaptureImplManager access this object by using a Unretained() |
| 8 // binding and tasks on the IO thread. It is then important that | 8 // binding and tasks on the IO thread. It is then important that |
| 9 // VideoCaptureImpl never post task to itself. All operations must be | 9 // VideoCaptureImpl never post task to itself. All operations must be |
| 10 // synchronous. | 10 // synchronous. |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 return; | 194 return; |
| 195 } | 195 } |
| 196 const bool inserted = | 196 const bool inserted = |
| 197 client_buffers_.insert(std::make_pair( | 197 client_buffers_.insert(std::make_pair( |
| 198 buffer_id, | 198 buffer_id, |
| 199 new ClientBuffer(std::move(shm), length))) | 199 new ClientBuffer(std::move(shm), length))) |
| 200 .second; | 200 .second; |
| 201 DCHECK(inserted); | 201 DCHECK(inserted); |
| 202 } | 202 } |
| 203 | 203 |
| 204 void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) { | 204 void VideoCaptureImpl::OnDelegateAdded(int32_t device_id) { |
| 205 DVLOG(1) << __func__ << " " << device_id; |
| 205 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 206 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 206 | 207 |
| 207 const auto& cb_iter = client_buffers_.find(buffer_id); | 208 device_id_ = device_id; |
| 208 if (cb_iter != client_buffers_.end()) { | 209 ClientInfoMap::iterator it = clients_pending_on_filter_.begin(); |
| 209 DCHECK(!cb_iter->second.get() || cb_iter->second->HasOneRef()) | 210 while (it != clients_pending_on_filter_.end()) { |
| 210 << "Instructed to delete buffer we are still using."; | 211 const int client_id = it->first; |
| 211 client_buffers_.erase(cb_iter); | 212 const ClientInfo client_info = it->second; |
| 213 clients_pending_on_filter_.erase(it++); |
| 214 StartCapture(client_id, client_info.params, client_info.state_update_cb, |
| 215 client_info.deliver_frame_cb); |
| 212 } | 216 } |
| 213 } | 217 } |
| 214 | 218 |
| 215 void VideoCaptureImpl::OnBufferReceived( | 219 void VideoCaptureImpl::OnStateChanged(mojom::VideoCaptureState state) { |
| 216 int buffer_id, | 220 DVLOG(1) << __func__ << " state: " << state; |
| 217 base::TimeDelta timestamp, | |
| 218 const base::DictionaryValue& metadata, | |
| 219 media::VideoPixelFormat pixel_format, | |
| 220 media::VideoFrame::StorageType storage_type, | |
| 221 const gfx::Size& coded_size, | |
| 222 const gfx::Rect& visible_rect) { | |
| 223 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 221 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 224 DCHECK_EQ(media::PIXEL_FORMAT_I420, pixel_format); | 222 |
| 225 DCHECK_EQ(media::VideoFrame::STORAGE_SHMEM, storage_type); | 223 switch (state) { |
| 224 case mojom::VideoCaptureState::STARTED: |
| 225 // Capture has started in the browser process. Since we have already |
| 226 // told all clients that we have started there's nothing to do. |
| 227 break; |
| 228 case mojom::VideoCaptureState::STOPPED: |
| 229 state_ = VIDEO_CAPTURE_STATE_STOPPED; |
| 230 client_buffers_.clear(); |
| 231 weak_factory_.InvalidateWeakPtrs(); |
| 232 if (!clients_.empty() || !clients_pending_on_restart_.empty()) |
| 233 RestartCapture(); |
| 234 break; |
| 235 case mojom::VideoCaptureState::PAUSED: |
| 236 for (const auto& client : clients_) |
| 237 client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_PAUSED); |
| 238 break; |
| 239 case mojom::VideoCaptureState::RESUMED: |
| 240 for (const auto& client : clients_) |
| 241 client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_RESUMED); |
| 242 break; |
| 243 case mojom::VideoCaptureState::FAILED: |
| 244 for (const auto& client : clients_) |
| 245 client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_ERROR); |
| 246 clients_.clear(); |
| 247 state_ = VIDEO_CAPTURE_STATE_ERROR; |
| 248 break; |
| 249 case mojom::VideoCaptureState::ENDED: |
| 250 // We'll only notify the client that the stream has stopped. |
| 251 for (const auto& client : clients_) |
| 252 client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED); |
| 253 clients_.clear(); |
| 254 state_ = VIDEO_CAPTURE_STATE_ENDED; |
| 255 break; |
| 256 } |
| 257 } |
| 258 |
| 259 void VideoCaptureImpl::OnBufferReady(int32_t buffer_id, |
| 260 mojom::VideoFrameInfoPtr info) { |
| 261 DVLOG(1) << __func__ << " buffer_id: " << buffer_id; |
| 262 |
| 263 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 264 DCHECK_EQ(media::mojom::VideoFormat::I420, info->pixel_format); |
| 265 DCHECK_EQ(media::PIXEL_STORAGE_CPU, info->storage_type); |
| 226 | 266 |
| 227 if (state_ != VIDEO_CAPTURE_STATE_STARTED || | 267 if (state_ != VIDEO_CAPTURE_STATE_STARTED || |
| 228 pixel_format != media::PIXEL_FORMAT_I420 || | 268 info->pixel_format != media::mojom::VideoFormat::I420 || |
| 229 storage_type != media::VideoFrame::STORAGE_SHMEM) { | 269 info->storage_type != media::PIXEL_STORAGE_CPU) { |
| 230 GetVideoCaptureHost()->ReleaseBuffer(device_id_, buffer_id, | 270 GetVideoCaptureHost()->ReleaseBuffer(device_id_, buffer_id, |
| 231 gpu::SyncToken(), -1.0); | 271 gpu::SyncToken(), -1.0); |
| 232 return; | 272 return; |
| 233 } | 273 } |
| 234 | 274 |
| 235 base::TimeTicks reference_time; | 275 base::TimeTicks reference_time; |
| 236 media::VideoFrameMetadata frame_metadata; | 276 media::VideoFrameMetadata frame_metadata; |
| 237 frame_metadata.MergeInternalValuesFrom(metadata); | 277 frame_metadata.MergeInternalValuesFrom(info->metadata); |
| 238 const bool success = frame_metadata.GetTimeTicks( | 278 const bool success = frame_metadata.GetTimeTicks( |
| 239 media::VideoFrameMetadata::REFERENCE_TIME, &reference_time); | 279 media::VideoFrameMetadata::REFERENCE_TIME, &reference_time); |
| 240 DCHECK(success); | 280 DCHECK(success); |
| 241 | 281 |
| 242 if (first_frame_ref_time_.is_null()) | 282 if (first_frame_ref_time_.is_null()) |
| 243 first_frame_ref_time_ = reference_time; | 283 first_frame_ref_time_ = reference_time; |
| 244 | 284 |
| 245 // If the timestamp is not prepared, we use reference time to make a rough | 285 // If the timestamp is not prepared, we use reference time to make a rough |
| 246 // estimate. e.g. ThreadSafeCaptureOracle::DidCaptureFrame(). | 286 // estimate. e.g. ThreadSafeCaptureOracle::DidCaptureFrame(). |
| 247 // TODO(miu): Fix upstream capturers to always set timestamp and reference | 287 // TODO(miu): Fix upstream capturers to always set timestamp and reference |
| 248 // time. See http://crbug/618407/ for tracking. | 288 // time. See http://crbug/618407/ for tracking. |
| 249 if (timestamp.is_zero()) | 289 if (info->timestamp.is_zero()) |
| 250 timestamp = reference_time - first_frame_ref_time_; | 290 info->timestamp = reference_time - first_frame_ref_time_; |
| 251 | 291 |
| 252 // TODO(qiangchen): Change the metric name to "reference_time" and | 292 // TODO(qiangchen): Change the metric name to "reference_time" and |
| 253 // "timestamp", so that we have consistent naming everywhere. | 293 // "timestamp", so that we have consistent naming everywhere. |
| 254 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc | 294 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc |
| 255 TRACE_EVENT_INSTANT2("cast_perf_test", "OnBufferReceived", | 295 TRACE_EVENT_INSTANT2("cast_perf_test", "OnBufferReceived", |
| 256 TRACE_EVENT_SCOPE_THREAD, "timestamp", | 296 TRACE_EVENT_SCOPE_THREAD, "timestamp", |
| 257 (reference_time - base::TimeTicks()).InMicroseconds(), | 297 (reference_time - base::TimeTicks()).InMicroseconds(), |
| 258 "time_delta", timestamp.InMicroseconds()); | 298 "time_delta", info->timestamp.InMicroseconds()); |
| 259 | 299 |
| 260 const auto& iter = client_buffers_.find(buffer_id); | 300 const auto& iter = client_buffers_.find(buffer_id); |
| 261 DCHECK(iter != client_buffers_.end()); | 301 DCHECK(iter != client_buffers_.end()); |
| 262 const scoped_refptr<ClientBuffer> buffer = iter->second; | 302 const scoped_refptr<ClientBuffer> buffer = iter->second; |
| 263 scoped_refptr<media::VideoFrame> frame = | 303 scoped_refptr<media::VideoFrame> frame = |
| 264 media::VideoFrame::WrapExternalSharedMemory( | 304 media::VideoFrame::WrapExternalSharedMemory( |
| 265 pixel_format, coded_size, visible_rect, | 305 static_cast<media::VideoPixelFormat>(info->pixel_format), |
| 266 gfx::Size(visible_rect.width(), visible_rect.height()), | 306 info->coded_size, info->visible_rect, info->visible_rect.size(), |
| 267 reinterpret_cast<uint8_t*>(buffer->buffer()->memory()), | 307 reinterpret_cast<uint8_t*>(buffer->buffer()->memory()), |
| 268 buffer->buffer_size(), buffer->buffer()->handle(), | 308 buffer->buffer_size(), buffer->buffer()->handle(), |
| 269 0 /* shared_memory_offset */, timestamp); | 309 0 /* shared_memory_offset */, info->timestamp); |
| 270 if (!frame) { | 310 if (!frame) { |
| 271 GetVideoCaptureHost()->ReleaseBuffer(device_id_, buffer_id, | 311 GetVideoCaptureHost()->ReleaseBuffer(device_id_, buffer_id, |
| 272 gpu::SyncToken(), -1.0); | 312 gpu::SyncToken(), -1.0); |
| 273 return; | 313 return; |
| 274 } | 314 } |
| 275 | 315 |
| 276 BufferFinishedCallback buffer_finished_callback = media::BindToCurrentLoop( | 316 BufferFinishedCallback buffer_finished_callback = media::BindToCurrentLoop( |
| 277 base::Bind(&VideoCaptureImpl::OnClientBufferFinished, | 317 base::Bind(&VideoCaptureImpl::OnClientBufferFinished, |
| 278 weak_factory_.GetWeakPtr(), buffer_id, buffer)); | 318 weak_factory_.GetWeakPtr(), buffer_id, buffer)); |
| 279 std::unique_ptr<gpu::SyncToken> release_sync_token(new gpu::SyncToken); | 319 std::unique_ptr<gpu::SyncToken> release_sync_token(new gpu::SyncToken); |
| 280 frame->AddDestructionObserver( | 320 frame->AddDestructionObserver( |
| 281 base::Bind(&VideoCaptureImpl::DidFinishConsumingFrame, frame->metadata(), | 321 base::Bind(&VideoCaptureImpl::DidFinishConsumingFrame, frame->metadata(), |
| 282 base::Passed(&release_sync_token), buffer_finished_callback)); | 322 base::Passed(&release_sync_token), buffer_finished_callback)); |
| 283 | 323 |
| 284 frame->metadata()->MergeInternalValuesFrom(metadata); | 324 frame->metadata()->MergeInternalValuesFrom(info->metadata); |
| 285 | 325 |
| 286 // TODO(qiangchen): Dive into the full code path to let frame metadata hold | 326 // TODO(qiangchen): Dive into the full code path to let frame metadata hold |
| 287 // reference time rather than using an extra parameter. | 327 // reference time rather than using an extra parameter. |
| 288 for (const auto& client : clients_) | 328 for (const auto& client : clients_) |
| 289 client.second.deliver_frame_cb.Run(frame, reference_time); | 329 client.second.deliver_frame_cb.Run(frame, reference_time); |
| 290 } | 330 } |
| 291 | 331 |
| 292 void VideoCaptureImpl::OnDelegateAdded(int32_t device_id) { | 332 void VideoCaptureImpl::OnBufferDestroyed(int32_t buffer_id) { |
| 293 DVLOG(1) << __func__ << " " << device_id; | |
| 294 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 333 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 295 | 334 |
| 296 device_id_ = device_id; | 335 const auto& cb_iter = client_buffers_.find(buffer_id); |
| 297 ClientInfoMap::iterator it = clients_pending_on_filter_.begin(); | 336 if (cb_iter != client_buffers_.end()) { |
| 298 while (it != clients_pending_on_filter_.end()) { | 337 DCHECK(!cb_iter->second.get() || cb_iter->second->HasOneRef()) |
| 299 const int client_id = it->first; | 338 << "Instructed to delete buffer we are still using."; |
| 300 const ClientInfo client_info = it->second; | 339 client_buffers_.erase(cb_iter); |
| 301 clients_pending_on_filter_.erase(it++); | |
| 302 StartCapture(client_id, client_info.params, client_info.state_update_cb, | |
| 303 client_info.deliver_frame_cb); | |
| 304 } | 340 } |
| 305 } | 341 } |
| 306 | 342 |
| 307 void VideoCaptureImpl::OnStateChanged(mojom::VideoCaptureState state) { | |
| 308 DVLOG(1) << __func__ << " state: " << state; | |
| 309 DCHECK(io_task_runner_->BelongsToCurrentThread()); | |
| 310 | |
| 311 switch (state) { | |
| 312 case mojom::VideoCaptureState::STARTED: | |
| 313 // Capture has started in the browser process. Since we have already | |
| 314 // told all clients that we have started there's nothing to do. | |
| 315 break; | |
| 316 case mojom::VideoCaptureState::STOPPED: | |
| 317 state_ = VIDEO_CAPTURE_STATE_STOPPED; | |
| 318 client_buffers_.clear(); | |
| 319 weak_factory_.InvalidateWeakPtrs(); | |
| 320 if (!clients_.empty() || !clients_pending_on_restart_.empty()) | |
| 321 RestartCapture(); | |
| 322 break; | |
| 323 case mojom::VideoCaptureState::PAUSED: | |
| 324 for (const auto& client : clients_) | |
| 325 client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_PAUSED); | |
| 326 break; | |
| 327 case mojom::VideoCaptureState::RESUMED: | |
| 328 for (const auto& client : clients_) | |
| 329 client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_RESUMED); | |
| 330 break; | |
| 331 case mojom::VideoCaptureState::FAILED: | |
| 332 for (const auto& client : clients_) | |
| 333 client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_ERROR); | |
| 334 clients_.clear(); | |
| 335 state_ = VIDEO_CAPTURE_STATE_ERROR; | |
| 336 break; | |
| 337 case mojom::VideoCaptureState::ENDED: | |
| 338 // We'll only notify the client that the stream has stopped. | |
| 339 for (const auto& client : clients_) | |
| 340 client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED); | |
| 341 clients_.clear(); | |
| 342 state_ = VIDEO_CAPTURE_STATE_ENDED; | |
| 343 break; | |
| 344 } | |
| 345 } | |
| 346 | |
| 347 void VideoCaptureImpl::OnClientBufferFinished( | 343 void VideoCaptureImpl::OnClientBufferFinished( |
| 348 int buffer_id, | 344 int buffer_id, |
| 349 const scoped_refptr<ClientBuffer>& /* ignored_buffer */, | 345 const scoped_refptr<ClientBuffer>& /* ignored_buffer */, |
| 350 const gpu::SyncToken& release_sync_token, | 346 const gpu::SyncToken& release_sync_token, |
| 351 double consumer_resource_utilization) { | 347 double consumer_resource_utilization) { |
| 352 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 348 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 353 GetVideoCaptureHost()->ReleaseBuffer( | 349 GetVideoCaptureHost()->ReleaseBuffer( |
| 354 device_id_, buffer_id, release_sync_token, consumer_resource_utilization); | 350 device_id_, buffer_id, release_sync_token, consumer_resource_utilization); |
| 355 } | 351 } |
| 356 | 352 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 449 double consumer_resource_utilization = -1.0; | 445 double consumer_resource_utilization = -1.0; |
| 450 if (!metadata->GetDouble(media::VideoFrameMetadata::RESOURCE_UTILIZATION, | 446 if (!metadata->GetDouble(media::VideoFrameMetadata::RESOURCE_UTILIZATION, |
| 451 &consumer_resource_utilization)) { | 447 &consumer_resource_utilization)) { |
| 452 consumer_resource_utilization = -1.0; | 448 consumer_resource_utilization = -1.0; |
| 453 } | 449 } |
| 454 | 450 |
| 455 callback_to_io_thread.Run(*release_sync_token, consumer_resource_utilization); | 451 callback_to_io_thread.Run(*release_sync_token, consumer_resource_utilization); |
| 456 } | 452 } |
| 457 | 453 |
| 458 } // namespace content | 454 } // namespace content |
| OLD | NEW |