| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/cast/sender/external_video_encoder.h" | 5 #include "media/cast/sender/external_video_encoder.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/memory/scoped_vector.h" | 9 #include "base/memory/scoped_vector.h" |
| 10 #include "base/memory/shared_memory.h" | 10 #include "base/memory/shared_memory.h" |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 int max_frame_rate, | 65 int max_frame_rate, |
| 66 const StatusChangeCallback& status_change_cb, | 66 const StatusChangeCallback& status_change_cb, |
| 67 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) | 67 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) |
| 68 : cast_environment_(cast_environment), | 68 : cast_environment_(cast_environment), |
| 69 task_runner_(encoder_task_runner), | 69 task_runner_(encoder_task_runner), |
| 70 max_frame_rate_(max_frame_rate), | 70 max_frame_rate_(max_frame_rate), |
| 71 status_change_cb_(status_change_cb), | 71 status_change_cb_(status_change_cb), |
| 72 create_video_encode_memory_cb_(create_video_encode_memory_cb), | 72 create_video_encode_memory_cb_(create_video_encode_memory_cb), |
| 73 video_encode_accelerator_(vea.Pass()), | 73 video_encode_accelerator_(vea.Pass()), |
| 74 encoder_active_(false), | 74 encoder_active_(false), |
| 75 last_encoded_frame_id_(kStartFrameId), | 75 next_frame_id_(0u), |
| 76 key_frame_encountered_(false) { | 76 key_frame_encountered_(false) { |
| 77 } | 77 } |
| 78 | 78 |
| 79 base::SingleThreadTaskRunner* task_runner() const { | 79 base::SingleThreadTaskRunner* task_runner() const { |
| 80 return task_runner_.get(); | 80 return task_runner_.get(); |
| 81 } | 81 } |
| 82 | 82 |
| 83 void Initialize(const gfx::Size& frame_size, | 83 void Initialize(const gfx::Size& frame_size, |
| 84 VideoCodecProfile codec_profile, | 84 VideoCodecProfile codec_profile, |
| 85 int start_bit_rate) { | 85 int start_bit_rate, |
| 86 uint32 first_frame_id) { |
| 86 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 87 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 87 DCHECK(!frame_size.IsEmpty()); | |
| 88 | 88 |
| 89 encoder_active_ = video_encode_accelerator_->Initialize( | 89 encoder_active_ = video_encode_accelerator_->Initialize( |
| 90 media::VideoFrame::I420, | 90 media::VideoFrame::I420, |
| 91 frame_size, | 91 frame_size, |
| 92 codec_profile, | 92 codec_profile, |
| 93 start_bit_rate, | 93 start_bit_rate, |
| 94 this); | 94 this); |
| 95 next_frame_id_ = first_frame_id; |
| 95 | 96 |
| 96 UMA_HISTOGRAM_BOOLEAN("Cast.Sender.VideoEncodeAcceleratorInitializeSuccess", | 97 UMA_HISTOGRAM_BOOLEAN("Cast.Sender.VideoEncodeAcceleratorInitializeSuccess", |
| 97 encoder_active_); | 98 encoder_active_); |
| 98 | 99 |
| 99 cast_environment_->PostTask( | 100 cast_environment_->PostTask( |
| 100 CastEnvironment::MAIN, | 101 CastEnvironment::MAIN, |
| 101 FROM_HERE, | 102 FROM_HERE, |
| 102 base::Bind(status_change_cb_, | 103 base::Bind(status_change_cb_, |
| 103 encoder_active_ ? STATUS_INITIALIZED : | 104 encoder_active_ ? STATUS_INITIALIZED : |
| 104 STATUS_CODEC_INIT_FAILED)); | 105 STATUS_CODEC_INIT_FAILED)); |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 // TODO(miu): Should |stream_header_| be an std::ostringstream for | 197 // TODO(miu): Should |stream_header_| be an std::ostringstream for |
| 197 // performance reasons? | 198 // performance reasons? |
| 198 stream_header_.append(static_cast<const char*>(output_buffer->memory()), | 199 stream_header_.append(static_cast<const char*>(output_buffer->memory()), |
| 199 payload_size); | 200 payload_size); |
| 200 } else if (!in_progress_frame_encodes_.empty()) { | 201 } else if (!in_progress_frame_encodes_.empty()) { |
| 201 const InProgressFrameEncode& request = in_progress_frame_encodes_.front(); | 202 const InProgressFrameEncode& request = in_progress_frame_encodes_.front(); |
| 202 | 203 |
| 203 scoped_ptr<EncodedFrame> encoded_frame(new EncodedFrame()); | 204 scoped_ptr<EncodedFrame> encoded_frame(new EncodedFrame()); |
| 204 encoded_frame->dependency = key_frame ? EncodedFrame::KEY : | 205 encoded_frame->dependency = key_frame ? EncodedFrame::KEY : |
| 205 EncodedFrame::DEPENDENT; | 206 EncodedFrame::DEPENDENT; |
| 206 encoded_frame->frame_id = ++last_encoded_frame_id_; | 207 encoded_frame->frame_id = next_frame_id_++; |
| 207 if (key_frame) | 208 if (key_frame) |
| 208 encoded_frame->referenced_frame_id = encoded_frame->frame_id; | 209 encoded_frame->referenced_frame_id = encoded_frame->frame_id; |
| 209 else | 210 else |
| 210 encoded_frame->referenced_frame_id = encoded_frame->frame_id - 1; | 211 encoded_frame->referenced_frame_id = encoded_frame->frame_id - 1; |
| 211 encoded_frame->rtp_timestamp = request.rtp_timestamp; | 212 encoded_frame->rtp_timestamp = request.rtp_timestamp; |
| 212 encoded_frame->reference_time = request.reference_time; | 213 encoded_frame->reference_time = request.reference_time; |
| 213 if (!stream_header_.empty()) { | 214 if (!stream_header_.empty()) { |
| 214 encoded_frame->data = stream_header_; | 215 encoded_frame->data = stream_header_; |
| 215 stream_header_.clear(); | 216 stream_header_.clear(); |
| 216 } | 217 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 } | 284 } |
| 284 } | 285 } |
| 285 | 286 |
| 286 const scoped_refptr<CastEnvironment> cast_environment_; | 287 const scoped_refptr<CastEnvironment> cast_environment_; |
| 287 const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 288 const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| 288 const int max_frame_rate_; | 289 const int max_frame_rate_; |
| 289 const StatusChangeCallback status_change_cb_; // Must be run on MAIN thread. | 290 const StatusChangeCallback status_change_cb_; // Must be run on MAIN thread. |
| 290 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; | 291 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; |
| 291 scoped_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; | 292 scoped_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; |
| 292 bool encoder_active_; | 293 bool encoder_active_; |
| 293 uint32 last_encoded_frame_id_; | 294 uint32 next_frame_id_; |
| 294 bool key_frame_encountered_; | 295 bool key_frame_encountered_; |
| 295 std::string stream_header_; | 296 std::string stream_header_; |
| 296 | 297 |
| 297 // Shared memory buffers for output with the VideoAccelerator. | 298 // Shared memory buffers for output with the VideoAccelerator. |
| 298 ScopedVector<base::SharedMemory> output_buffers_; | 299 ScopedVector<base::SharedMemory> output_buffers_; |
| 299 | 300 |
| 300 // FIFO list. | 301 // FIFO list. |
| 301 std::list<InProgressFrameEncode> in_progress_frame_encodes_; | 302 std::list<InProgressFrameEncode> in_progress_frame_encodes_; |
| 302 | 303 |
| 303 DISALLOW_COPY_AND_ASSIGN(VEAClientImpl); | 304 DISALLOW_COPY_AND_ASSIGN(VEAClientImpl); |
| 304 }; | 305 }; |
| 305 | 306 |
| 307 // static |
| 308 bool ExternalVideoEncoder::IsSupported(const VideoSenderConfig& video_config) { |
| 309 if (video_config.codec != CODEC_VIDEO_VP8 && |
| 310 video_config.codec != CODEC_VIDEO_H264) |
| 311 return false; |
| 312 |
| 313 // TODO(miu): "Layering hooks" are needed to be able to query outside of |
| 314 // libmedia, to determine whether the system provides a hardware encoder. For |
| 315 // now, assume that this was already checked by this point. |
| 316 // http://crbug.com/454029 |
| 317 return video_config.use_external_encoder; |
| 318 } |
| 319 |
| 306 ExternalVideoEncoder::ExternalVideoEncoder( | 320 ExternalVideoEncoder::ExternalVideoEncoder( |
| 307 const scoped_refptr<CastEnvironment>& cast_environment, | 321 const scoped_refptr<CastEnvironment>& cast_environment, |
| 308 const VideoSenderConfig& video_config, | 322 const VideoSenderConfig& video_config, |
| 309 const gfx::Size& frame_size, | 323 const gfx::Size& frame_size, |
| 324 uint32 first_frame_id, |
| 310 const StatusChangeCallback& status_change_cb, | 325 const StatusChangeCallback& status_change_cb, |
| 311 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, | 326 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, |
| 312 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) | 327 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) |
| 313 : cast_environment_(cast_environment), | 328 : cast_environment_(cast_environment), |
| 314 create_video_encode_memory_cb_(create_video_encode_memory_cb), | 329 create_video_encode_memory_cb_(create_video_encode_memory_cb), |
| 330 frame_size_(frame_size), |
| 315 bit_rate_(video_config.start_bitrate), | 331 bit_rate_(video_config.start_bitrate), |
| 316 key_frame_requested_(false), | 332 key_frame_requested_(false), |
| 317 weak_factory_(this) { | 333 weak_factory_(this) { |
| 318 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 334 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 319 DCHECK_GT(video_config.max_frame_rate, 0); | 335 DCHECK_GT(video_config.max_frame_rate, 0); |
| 320 DCHECK(!frame_size.IsEmpty()); | 336 DCHECK(!frame_size_.IsEmpty()); |
| 321 DCHECK(!status_change_cb.is_null()); | 337 DCHECK(!status_change_cb.is_null()); |
| 322 DCHECK(!create_vea_cb.is_null()); | 338 DCHECK(!create_vea_cb.is_null()); |
| 323 DCHECK(!create_video_encode_memory_cb_.is_null()); | 339 DCHECK(!create_video_encode_memory_cb_.is_null()); |
| 324 DCHECK_GT(bit_rate_, 0); | 340 DCHECK_GT(bit_rate_, 0); |
| 325 | 341 |
| 326 VideoCodecProfile codec_profile; | |
| 327 switch (video_config.codec) { | |
| 328 case CODEC_VIDEO_VP8: | |
| 329 codec_profile = media::VP8PROFILE_ANY; | |
| 330 break; | |
| 331 case CODEC_VIDEO_H264: | |
| 332 codec_profile = media::H264PROFILE_MAIN; | |
| 333 break; | |
| 334 case CODEC_VIDEO_FAKE: | |
| 335 NOTREACHED() << "Fake software video encoder cannot be external"; | |
| 336 // ...flow through to next case... | |
| 337 default: | |
| 338 cast_environment_->PostTask( | |
| 339 CastEnvironment::MAIN, | |
| 340 FROM_HERE, | |
| 341 base::Bind(status_change_cb, STATUS_UNSUPPORTED_CODEC)); | |
| 342 return; | |
| 343 } | |
| 344 | |
| 345 create_vea_cb.Run( | 342 create_vea_cb.Run( |
| 346 base::Bind(&ExternalVideoEncoder::OnCreateVideoEncodeAccelerator, | 343 base::Bind(&ExternalVideoEncoder::OnCreateVideoEncodeAccelerator, |
| 347 weak_factory_.GetWeakPtr(), | 344 weak_factory_.GetWeakPtr(), |
| 348 frame_size, | 345 video_config, |
| 349 codec_profile, | 346 first_frame_id, |
| 350 video_config.max_frame_rate, | |
| 351 status_change_cb)); | 347 status_change_cb)); |
| 352 } | 348 } |
| 353 | 349 |
| 354 ExternalVideoEncoder::~ExternalVideoEncoder() { | 350 ExternalVideoEncoder::~ExternalVideoEncoder() { |
| 355 } | 351 } |
| 356 | 352 |
| 357 bool ExternalVideoEncoder::CanEncodeVariedFrameSizes() const { | |
| 358 return false; | |
| 359 } | |
| 360 | |
| 361 bool ExternalVideoEncoder::EncodeVideoFrame( | 353 bool ExternalVideoEncoder::EncodeVideoFrame( |
| 362 const scoped_refptr<media::VideoFrame>& video_frame, | 354 const scoped_refptr<media::VideoFrame>& video_frame, |
| 363 const base::TimeTicks& reference_time, | 355 const base::TimeTicks& reference_time, |
| 364 const FrameEncodedCallback& frame_encoded_callback) { | 356 const FrameEncodedCallback& frame_encoded_callback) { |
| 365 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 357 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 366 DCHECK(!video_frame->visible_rect().IsEmpty()); | |
| 367 DCHECK(!frame_encoded_callback.is_null()); | 358 DCHECK(!frame_encoded_callback.is_null()); |
| 368 | 359 |
| 369 if (!client_) | 360 if (!client_ || video_frame->visible_rect().size() != frame_size_) |
| 370 return false; // Not ready. | 361 return false; |
| 371 | 362 |
| 372 client_->task_runner()->PostTask(FROM_HERE, | 363 client_->task_runner()->PostTask(FROM_HERE, |
| 373 base::Bind(&VEAClientImpl::EncodeVideoFrame, | 364 base::Bind(&VEAClientImpl::EncodeVideoFrame, |
| 374 client_, | 365 client_, |
| 375 video_frame, | 366 video_frame, |
| 376 reference_time, | 367 reference_time, |
| 377 key_frame_requested_, | 368 key_frame_requested_, |
| 378 frame_encoded_callback)); | 369 frame_encoded_callback)); |
| 379 key_frame_requested_ = false; | 370 key_frame_requested_ = false; |
| 380 return true; | 371 return true; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 394 void ExternalVideoEncoder::GenerateKeyFrame() { | 385 void ExternalVideoEncoder::GenerateKeyFrame() { |
| 395 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 386 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 396 key_frame_requested_ = true; | 387 key_frame_requested_ = true; |
| 397 } | 388 } |
| 398 | 389 |
| 399 void ExternalVideoEncoder::LatestFrameIdToReference(uint32 /*frame_id*/) { | 390 void ExternalVideoEncoder::LatestFrameIdToReference(uint32 /*frame_id*/) { |
| 400 // Do nothing. Not supported. | 391 // Do nothing. Not supported. |
| 401 } | 392 } |
| 402 | 393 |
| 403 void ExternalVideoEncoder::OnCreateVideoEncodeAccelerator( | 394 void ExternalVideoEncoder::OnCreateVideoEncodeAccelerator( |
| 404 const gfx::Size& frame_size, | 395 const VideoSenderConfig& video_config, |
| 405 VideoCodecProfile codec_profile, | 396 uint32 first_frame_id, |
| 406 int max_frame_rate, | |
| 407 const StatusChangeCallback& status_change_cb, | 397 const StatusChangeCallback& status_change_cb, |
| 408 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner, | 398 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner, |
| 409 scoped_ptr<media::VideoEncodeAccelerator> vea) { | 399 scoped_ptr<media::VideoEncodeAccelerator> vea) { |
| 410 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 400 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 411 | 401 |
| 412 // The callback will be invoked with null pointers in the case where the | 402 // The callback will be invoked with null pointers in the case where the |
| 413 // system does not support or lacks the resources to provide GPU-accelerated | 403 // system does not support or lacks the resources to provide GPU-accelerated |
| 414 // video encoding. | 404 // video encoding. |
| 415 if (!encoder_task_runner || !vea) { | 405 if (!encoder_task_runner || !vea) { |
| 416 cast_environment_->PostTask( | 406 cast_environment_->PostTask( |
| 417 CastEnvironment::MAIN, | 407 CastEnvironment::MAIN, |
| 418 FROM_HERE, | 408 FROM_HERE, |
| 419 base::Bind(status_change_cb, STATUS_CODEC_INIT_FAILED)); | 409 base::Bind(status_change_cb, STATUS_CODEC_INIT_FAILED)); |
| 420 return; | 410 return; |
| 421 } | 411 } |
| 422 | 412 |
| 413 VideoCodecProfile codec_profile; |
| 414 switch (video_config.codec) { |
| 415 case CODEC_VIDEO_VP8: |
| 416 codec_profile = media::VP8PROFILE_ANY; |
| 417 break; |
| 418 case CODEC_VIDEO_H264: |
| 419 codec_profile = media::H264PROFILE_MAIN; |
| 420 break; |
| 421 case CODEC_VIDEO_FAKE: |
| 422 NOTREACHED() << "Fake software video encoder cannot be external"; |
| 423 // ...flow through to next case... |
| 424 default: |
| 425 cast_environment_->PostTask( |
| 426 CastEnvironment::MAIN, |
| 427 FROM_HERE, |
| 428 base::Bind(status_change_cb, STATUS_UNSUPPORTED_CODEC)); |
| 429 return; |
| 430 } |
| 431 |
| 423 DCHECK(!client_); | 432 DCHECK(!client_); |
| 424 client_ = new VEAClientImpl(cast_environment_, | 433 client_ = new VEAClientImpl(cast_environment_, |
| 425 encoder_task_runner, | 434 encoder_task_runner, |
| 426 vea.Pass(), | 435 vea.Pass(), |
| 427 max_frame_rate, | 436 video_config.max_frame_rate, |
| 428 status_change_cb, | 437 status_change_cb, |
| 429 create_video_encode_memory_cb_); | 438 create_video_encode_memory_cb_); |
| 430 client_->task_runner()->PostTask(FROM_HERE, | 439 client_->task_runner()->PostTask(FROM_HERE, |
| 431 base::Bind(&VEAClientImpl::Initialize, | 440 base::Bind(&VEAClientImpl::Initialize, |
| 432 client_, | 441 client_, |
| 433 frame_size, | 442 frame_size_, |
| 434 codec_profile, | 443 codec_profile, |
| 435 bit_rate_)); | 444 bit_rate_, |
| 445 first_frame_id)); |
| 446 } |
| 447 |
| 448 SizeAdaptableExternalVideoEncoder::SizeAdaptableExternalVideoEncoder( |
| 449 const scoped_refptr<CastEnvironment>& cast_environment, |
| 450 const VideoSenderConfig& video_config, |
| 451 const StatusChangeCallback& status_change_cb, |
| 452 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, |
| 453 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) |
| 454 : SizeAdaptableVideoEncoderBase(cast_environment, |
| 455 video_config, |
| 456 status_change_cb), |
| 457 create_vea_cb_(create_vea_cb), |
| 458 create_video_encode_memory_cb_(create_video_encode_memory_cb) {} |
| 459 |
| 460 SizeAdaptableExternalVideoEncoder::~SizeAdaptableExternalVideoEncoder() {} |
| 461 |
| 462 scoped_ptr<VideoEncoder> SizeAdaptableExternalVideoEncoder::CreateEncoder() { |
| 463 return scoped_ptr<VideoEncoder>(new ExternalVideoEncoder( |
| 464 cast_environment(), |
| 465 video_config(), |
| 466 frame_size(), |
| 467 last_frame_id() + 1, |
| 468 CreateEncoderStatusChangeCallback(), |
| 469 create_vea_cb_, |
| 470 create_video_encode_memory_cb_)); |
| 436 } | 471 } |
| 437 | 472 |
| 438 } // namespace cast | 473 } // namespace cast |
| 439 } // namespace media | 474 } // namespace media |
| OLD | NEW |