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 |