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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 // SingleThreadTaskRunner, except for the task_runner() accessor. | 56 // SingleThreadTaskRunner, except for the task_runner() accessor. |
57 class ExternalVideoEncoder::VEAClientImpl | 57 class ExternalVideoEncoder::VEAClientImpl |
58 : public VideoEncodeAccelerator::Client, | 58 : public VideoEncodeAccelerator::Client, |
59 public base::RefCountedThreadSafe<VEAClientImpl> { | 59 public base::RefCountedThreadSafe<VEAClientImpl> { |
60 public: | 60 public: |
61 VEAClientImpl( | 61 VEAClientImpl( |
62 const scoped_refptr<CastEnvironment>& cast_environment, | 62 const scoped_refptr<CastEnvironment>& cast_environment, |
63 const scoped_refptr<base::SingleThreadTaskRunner>& encoder_task_runner, | 63 const scoped_refptr<base::SingleThreadTaskRunner>& encoder_task_runner, |
64 scoped_ptr<media::VideoEncodeAccelerator> vea, | 64 scoped_ptr<media::VideoEncodeAccelerator> vea, |
65 int max_frame_rate, | 65 int max_frame_rate, |
| 66 const StatusChangeCallback& status_change_cb, |
66 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) | 67 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) |
67 : cast_environment_(cast_environment), | 68 : cast_environment_(cast_environment), |
68 task_runner_(encoder_task_runner), | 69 task_runner_(encoder_task_runner), |
69 max_frame_rate_(max_frame_rate), | 70 max_frame_rate_(max_frame_rate), |
| 71 status_change_cb_(status_change_cb), |
70 create_video_encode_memory_cb_(create_video_encode_memory_cb), | 72 create_video_encode_memory_cb_(create_video_encode_memory_cb), |
71 video_encode_accelerator_(vea.Pass()), | 73 video_encode_accelerator_(vea.Pass()), |
72 encoder_active_(false), | 74 encoder_active_(false), |
73 last_encoded_frame_id_(kStartFrameId), | 75 last_encoded_frame_id_(kStartFrameId), |
74 key_frame_encountered_(false) { | 76 key_frame_encountered_(false) { |
75 } | 77 } |
76 | 78 |
77 base::SingleThreadTaskRunner* task_runner() const { | 79 base::SingleThreadTaskRunner* task_runner() const { |
78 return task_runner_.get(); | 80 return task_runner_.get(); |
79 } | 81 } |
80 | 82 |
81 void Initialize(const gfx::Size& frame_size, | 83 void Initialize(const gfx::Size& frame_size, |
82 VideoCodecProfile codec_profile, | 84 VideoCodecProfile codec_profile, |
83 int start_bit_rate, | 85 int start_bit_rate) { |
84 const CastInitializationCallback& initialization_cb) { | |
85 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 86 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
86 DCHECK(!frame_size.IsEmpty()); | 87 DCHECK(!frame_size.IsEmpty()); |
87 | 88 |
88 encoder_active_ = video_encode_accelerator_->Initialize( | 89 encoder_active_ = video_encode_accelerator_->Initialize( |
89 media::VideoFrame::I420, | 90 media::VideoFrame::I420, |
90 frame_size, | 91 frame_size, |
91 codec_profile, | 92 codec_profile, |
92 start_bit_rate, | 93 start_bit_rate, |
93 this); | 94 this); |
94 | 95 |
95 UMA_HISTOGRAM_BOOLEAN("Cast.Sender.VideoEncodeAcceleratorInitializeSuccess", | 96 UMA_HISTOGRAM_BOOLEAN("Cast.Sender.VideoEncodeAcceleratorInitializeSuccess", |
96 encoder_active_); | 97 encoder_active_); |
97 | 98 |
98 if (!initialization_cb.is_null()) { | 99 cast_environment_->PostTask( |
99 cast_environment_->PostTask( | 100 CastEnvironment::MAIN, |
100 CastEnvironment::MAIN, | 101 FROM_HERE, |
101 FROM_HERE, | 102 base::Bind(status_change_cb_, |
102 base::Bind(initialization_cb, | 103 encoder_active_ ? STATUS_INITIALIZED : |
103 encoder_active_ ? STATUS_VIDEO_INITIALIZED : | 104 STATUS_CODEC_INIT_FAILED)); |
104 STATUS_HW_VIDEO_ENCODER_NOT_SUPPORTED)); | |
105 } | |
106 } | 105 } |
107 | 106 |
108 void SetBitRate(int bit_rate) { | 107 void SetBitRate(int bit_rate) { |
109 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 108 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
110 | 109 |
111 video_encode_accelerator_->RequestEncodingParametersChange(bit_rate, | 110 video_encode_accelerator_->RequestEncodingParametersChange(bit_rate, |
112 max_frame_rate_); | 111 max_frame_rate_); |
113 } | 112 } |
114 | 113 |
115 void EncodeVideoFrame( | 114 void EncodeVideoFrame( |
(...skipping 11 matching lines...) Expand all Loading... |
127 reference_time, | 126 reference_time, |
128 frame_encoded_callback)); | 127 frame_encoded_callback)); |
129 | 128 |
130 // BitstreamBufferReady will be called once the encoder is done. | 129 // BitstreamBufferReady will be called once the encoder is done. |
131 video_encode_accelerator_->Encode(video_frame, key_frame_requested); | 130 video_encode_accelerator_->Encode(video_frame, key_frame_requested); |
132 } | 131 } |
133 | 132 |
134 protected: | 133 protected: |
135 void NotifyError(VideoEncodeAccelerator::Error error) override { | 134 void NotifyError(VideoEncodeAccelerator::Error error) override { |
136 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 135 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
137 VLOG(1) << "ExternalVideoEncoder NotifyError: " << error; | 136 |
| 137 DCHECK(error != VideoEncodeAccelerator::kInvalidArgumentError && |
| 138 error != VideoEncodeAccelerator::kIllegalStateError); |
138 | 139 |
139 encoder_active_ = false; | 140 encoder_active_ = false; |
140 // TODO(miu): Plumbing is required to bubble this up to the CastSession and | 141 |
141 // beyond. | 142 cast_environment_->PostTask( |
| 143 CastEnvironment::MAIN, |
| 144 FROM_HERE, |
| 145 base::Bind(status_change_cb_, STATUS_CODEC_RUNTIME_ERROR)); |
| 146 |
142 // TODO(miu): Force-flush all |in_progress_frame_encodes_| immediately so | 147 // TODO(miu): Force-flush all |in_progress_frame_encodes_| immediately so |
143 // pending frames do not become stuck, freezing VideoSender. | 148 // pending frames do not become stuck, freezing VideoSender. |
144 } | 149 } |
145 | 150 |
146 // Called to allocate the input and output buffers. | 151 // Called to allocate the input and output buffers. |
147 void RequireBitstreamBuffers(unsigned int input_count, | 152 void RequireBitstreamBuffers(unsigned int input_count, |
148 const gfx::Size& input_coded_size, | 153 const gfx::Size& input_coded_size, |
149 size_t output_buffer_size) override { | 154 size_t output_buffer_size) override { |
150 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 155 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
151 | 156 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 video_encode_accelerator_->UseOutputBitstreamBuffer( | 279 video_encode_accelerator_->UseOutputBitstreamBuffer( |
275 media::BitstreamBuffer(static_cast<int32>(i), | 280 media::BitstreamBuffer(static_cast<int32>(i), |
276 output_buffers_[i]->handle(), | 281 output_buffers_[i]->handle(), |
277 output_buffers_[i]->mapped_size())); | 282 output_buffers_[i]->mapped_size())); |
278 } | 283 } |
279 } | 284 } |
280 | 285 |
281 const scoped_refptr<CastEnvironment> cast_environment_; | 286 const scoped_refptr<CastEnvironment> cast_environment_; |
282 const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 287 const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
283 const int max_frame_rate_; | 288 const int max_frame_rate_; |
| 289 const StatusChangeCallback status_change_cb_; // Must be run on MAIN thread. |
284 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; | 290 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; |
285 scoped_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; | 291 scoped_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; |
286 bool encoder_active_; | 292 bool encoder_active_; |
287 uint32 last_encoded_frame_id_; | 293 uint32 last_encoded_frame_id_; |
288 bool key_frame_encountered_; | 294 bool key_frame_encountered_; |
289 std::string stream_header_; | 295 std::string stream_header_; |
290 | 296 |
291 // Shared memory buffers for output with the VideoAccelerator. | 297 // Shared memory buffers for output with the VideoAccelerator. |
292 ScopedVector<base::SharedMemory> output_buffers_; | 298 ScopedVector<base::SharedMemory> output_buffers_; |
293 | 299 |
294 // FIFO list. | 300 // FIFO list. |
295 std::list<InProgressFrameEncode> in_progress_frame_encodes_; | 301 std::list<InProgressFrameEncode> in_progress_frame_encodes_; |
296 | 302 |
297 DISALLOW_COPY_AND_ASSIGN(VEAClientImpl); | 303 DISALLOW_COPY_AND_ASSIGN(VEAClientImpl); |
298 }; | 304 }; |
299 | 305 |
300 ExternalVideoEncoder::ExternalVideoEncoder( | 306 ExternalVideoEncoder::ExternalVideoEncoder( |
301 const scoped_refptr<CastEnvironment>& cast_environment, | 307 const scoped_refptr<CastEnvironment>& cast_environment, |
302 const VideoSenderConfig& video_config, | 308 const VideoSenderConfig& video_config, |
303 const gfx::Size& frame_size, | 309 const gfx::Size& frame_size, |
304 const CastInitializationCallback& initialization_cb, | 310 const StatusChangeCallback& status_change_cb, |
305 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, | 311 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, |
306 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) | 312 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) |
307 : cast_environment_(cast_environment), | 313 : cast_environment_(cast_environment), |
308 create_video_encode_memory_cb_(create_video_encode_memory_cb), | 314 create_video_encode_memory_cb_(create_video_encode_memory_cb), |
309 bit_rate_(video_config.start_bitrate), | 315 bit_rate_(video_config.start_bitrate), |
310 key_frame_requested_(false), | 316 key_frame_requested_(false), |
311 weak_factory_(this) { | 317 weak_factory_(this) { |
312 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 318 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
313 DCHECK_GT(video_config.max_frame_rate, 0); | 319 DCHECK_GT(video_config.max_frame_rate, 0); |
314 DCHECK(!frame_size.IsEmpty()); | 320 DCHECK(!frame_size.IsEmpty()); |
| 321 DCHECK(!status_change_cb.is_null()); |
315 DCHECK(!create_vea_cb.is_null()); | 322 DCHECK(!create_vea_cb.is_null()); |
316 DCHECK(!create_video_encode_memory_cb_.is_null()); | 323 DCHECK(!create_video_encode_memory_cb_.is_null()); |
317 DCHECK_GT(bit_rate_, 0); | 324 DCHECK_GT(bit_rate_, 0); |
318 | 325 |
319 VideoCodecProfile codec_profile; | 326 VideoCodecProfile codec_profile; |
320 switch (video_config.codec) { | 327 switch (video_config.codec) { |
321 case CODEC_VIDEO_VP8: | 328 case CODEC_VIDEO_VP8: |
322 codec_profile = media::VP8PROFILE_ANY; | 329 codec_profile = media::VP8PROFILE_ANY; |
323 break; | 330 break; |
324 case CODEC_VIDEO_H264: | 331 case CODEC_VIDEO_H264: |
325 codec_profile = media::H264PROFILE_MAIN; | 332 codec_profile = media::H264PROFILE_MAIN; |
326 break; | 333 break; |
327 case CODEC_VIDEO_FAKE: | 334 case CODEC_VIDEO_FAKE: |
328 NOTREACHED() << "Fake software video encoder cannot be external"; | 335 NOTREACHED() << "Fake software video encoder cannot be external"; |
329 // ...flow through to next case... | 336 // ...flow through to next case... |
330 default: | 337 default: |
331 cast_environment_->PostTask( | 338 cast_environment_->PostTask( |
332 CastEnvironment::MAIN, | 339 CastEnvironment::MAIN, |
333 FROM_HERE, | 340 FROM_HERE, |
334 base::Bind(initialization_cb, STATUS_HW_VIDEO_ENCODER_NOT_SUPPORTED)); | 341 base::Bind(status_change_cb, STATUS_UNSUPPORTED_CODEC)); |
335 return; | 342 return; |
336 } | 343 } |
337 | 344 |
338 create_vea_cb.Run( | 345 create_vea_cb.Run( |
339 base::Bind(&ExternalVideoEncoder::OnCreateVideoEncodeAccelerator, | 346 base::Bind(&ExternalVideoEncoder::OnCreateVideoEncodeAccelerator, |
340 weak_factory_.GetWeakPtr(), | 347 weak_factory_.GetWeakPtr(), |
341 frame_size, | 348 frame_size, |
342 codec_profile, | 349 codec_profile, |
343 video_config.max_frame_rate, | 350 video_config.max_frame_rate, |
344 initialization_cb)); | 351 status_change_cb)); |
345 } | 352 } |
346 | 353 |
347 ExternalVideoEncoder::~ExternalVideoEncoder() { | 354 ExternalVideoEncoder::~ExternalVideoEncoder() { |
348 } | 355 } |
349 | 356 |
350 bool ExternalVideoEncoder::CanEncodeVariedFrameSizes() const { | 357 bool ExternalVideoEncoder::CanEncodeVariedFrameSizes() const { |
351 return false; | 358 return false; |
352 } | 359 } |
353 | 360 |
354 bool ExternalVideoEncoder::EncodeVideoFrame( | 361 bool ExternalVideoEncoder::EncodeVideoFrame( |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 } | 397 } |
391 | 398 |
392 void ExternalVideoEncoder::LatestFrameIdToReference(uint32 /*frame_id*/) { | 399 void ExternalVideoEncoder::LatestFrameIdToReference(uint32 /*frame_id*/) { |
393 // Do nothing. Not supported. | 400 // Do nothing. Not supported. |
394 } | 401 } |
395 | 402 |
396 void ExternalVideoEncoder::OnCreateVideoEncodeAccelerator( | 403 void ExternalVideoEncoder::OnCreateVideoEncodeAccelerator( |
397 const gfx::Size& frame_size, | 404 const gfx::Size& frame_size, |
398 VideoCodecProfile codec_profile, | 405 VideoCodecProfile codec_profile, |
399 int max_frame_rate, | 406 int max_frame_rate, |
400 const CastInitializationCallback& initialization_cb, | 407 const StatusChangeCallback& status_change_cb, |
401 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner, | 408 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner, |
402 scoped_ptr<media::VideoEncodeAccelerator> vea) { | 409 scoped_ptr<media::VideoEncodeAccelerator> vea) { |
403 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 410 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
404 | 411 |
405 // The callback will be invoked with null pointers in the case where the | 412 // The callback will be invoked with null pointers in the case where the |
406 // system does not support or lacks the resources to provide GPU-accelerated | 413 // system does not support or lacks the resources to provide GPU-accelerated |
407 // video encoding. | 414 // video encoding. |
408 if (!encoder_task_runner || !vea) { | 415 if (!encoder_task_runner || !vea) { |
409 if (!initialization_cb.is_null()) { | 416 cast_environment_->PostTask( |
410 cast_environment_->PostTask( | 417 CastEnvironment::MAIN, |
411 CastEnvironment::MAIN, | 418 FROM_HERE, |
412 FROM_HERE, | 419 base::Bind(status_change_cb, STATUS_CODEC_INIT_FAILED)); |
413 base::Bind(initialization_cb, STATUS_INVALID_VIDEO_CONFIGURATION)); | |
414 } | |
415 return; | 420 return; |
416 } | 421 } |
417 | 422 |
418 DCHECK(!client_); | 423 DCHECK(!client_); |
419 client_ = new VEAClientImpl(cast_environment_, | 424 client_ = new VEAClientImpl(cast_environment_, |
420 encoder_task_runner, | 425 encoder_task_runner, |
421 vea.Pass(), | 426 vea.Pass(), |
422 max_frame_rate, | 427 max_frame_rate, |
| 428 status_change_cb, |
423 create_video_encode_memory_cb_); | 429 create_video_encode_memory_cb_); |
424 client_->task_runner()->PostTask(FROM_HERE, | 430 client_->task_runner()->PostTask(FROM_HERE, |
425 base::Bind(&VEAClientImpl::Initialize, | 431 base::Bind(&VEAClientImpl::Initialize, |
426 client_, | 432 client_, |
427 frame_size, | 433 frame_size, |
428 codec_profile, | 434 codec_profile, |
429 bit_rate_, | 435 bit_rate_)); |
430 initialization_cb)); | |
431 } | 436 } |
432 | 437 |
433 } // namespace cast | 438 } // namespace cast |
434 } // namespace media | 439 } // namespace media |
OLD | NEW |