Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(369)

Side by Side Diff: media/cast/sender/external_video_encoder.cc

Issue 1913503002: Memory copy the VideoFrame to match the requirement for HW encoders. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Used shared memory for encoder input buffer. Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« media/base/video_util.cc ('K') | « media/base/video_util.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <cmath> 7 #include <cmath>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/debug/crash_logging.h" 11 #include "base/debug/crash_logging.h"
12 #include "base/debug/dump_without_crashing.h" 12 #include "base/debug/dump_without_crashing.h"
13 #include "base/format_macros.h" 13 #include "base/format_macros.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/macros.h" 15 #include "base/macros.h"
16 #include "base/memory/scoped_vector.h" 16 #include "base/memory/scoped_vector.h"
17 #include "base/memory/shared_memory.h" 17 #include "base/memory/shared_memory.h"
18 #include "base/message_loop/message_loop.h" 18 #include "base/message_loop/message_loop.h"
19 #include "base/metrics/histogram.h" 19 #include "base/metrics/histogram.h"
20 #include "base/strings/stringprintf.h" 20 #include "base/strings/stringprintf.h"
21 #include "build/build_config.h" 21 #include "build/build_config.h"
22 #include "media/base/bind_to_current_loop.h"
22 #include "media/base/video_frame.h" 23 #include "media/base/video_frame.h"
23 #include "media/base/video_types.h" 24 #include "media/base/video_types.h"
24 #include "media/base/video_util.h" 25 #include "media/base/video_util.h"
25 #include "media/cast/cast_config.h" 26 #include "media/cast/cast_config.h"
26 #include "media/cast/cast_defines.h" 27 #include "media/cast/cast_defines.h"
27 #include "media/cast/common/rtp_time.h" 28 #include "media/cast/common/rtp_time.h"
28 #include "media/cast/logging/logging_defines.h" 29 #include "media/cast/logging/logging_defines.h"
29 #include "media/cast/net/cast_transport_config.h" 30 #include "media/cast/net/cast_transport_config.h"
30 #include "media/cast/sender/vp8_quantizer_parser.h" 31 #include "media/cast/sender/vp8_quantizer_parser.h"
31 #include "media/filters/h264_parser.h" 32 #include "media/filters/h264_parser.h"
32 33
33 namespace { 34 namespace {
34 35
35 enum { MAX_H264_QUANTIZER = 51 }; 36 enum { MAX_H264_QUANTIZER = 51 };
37
38 // Number of buffers for encoded bit stream.
36 static const size_t kOutputBufferCount = 3; 39 static const size_t kOutputBufferCount = 3;
37 40
41 // Number of extra buffers for encoder input. The input buffers are used to copy
42 // the video stream to match the required coded size.
43 static const size_t kExtraInputBufferCount = 3;
44
38 } // namespace 45 } // namespace
39 46
40 namespace media { 47 namespace media {
41 namespace cast { 48 namespace cast {
42 49
43 // Container for the associated data of a video frame being processed. 50 // Container for the associated data of a video frame being processed.
44 struct InProgressFrameEncode { 51 struct InProgressFrameEncode {
45 // The source content to encode. 52 // The source content to encode.
46 const scoped_refptr<VideoFrame> video_frame; 53 const scoped_refptr<VideoFrame> video_frame;
47 54
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 } 135 }
129 136
130 void SetBitRate(int bit_rate) { 137 void SetBitRate(int bit_rate) {
131 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 138 DCHECK(task_runner_->RunsTasksOnCurrentThread());
132 139
133 requested_bit_rate_ = bit_rate; 140 requested_bit_rate_ = bit_rate;
134 video_encode_accelerator_->RequestEncodingParametersChange(bit_rate, 141 video_encode_accelerator_->RequestEncodingParametersChange(bit_rate,
135 max_frame_rate_); 142 max_frame_rate_);
136 } 143 }
137 144
145 // The destruction call back of the copied video frame to free its use of
146 // the input buffer.
147 void OnFinishEncodeFrame(int index) {
miu 2016/04/30 00:41:14 naming nit: Since this is only used when we have t
xjz 2016/05/03 01:17:59 Done.
148 DCHECK(task_runner_->RunsTasksOnCurrentThread());
149 DCHECK_GE(index, 0);
150 DCHECK_LT(index, static_cast<int>(input_buffers_.size()));
151 free_input_buffer_index_.push_back(index);
152 }
153
138 void EncodeVideoFrame( 154 void EncodeVideoFrame(
139 const scoped_refptr<media::VideoFrame>& video_frame, 155 const scoped_refptr<media::VideoFrame>& video_frame,
140 const base::TimeTicks& reference_time, 156 const base::TimeTicks& reference_time,
141 bool key_frame_requested, 157 bool key_frame_requested,
142 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) { 158 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) {
143 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 159 DCHECK(task_runner_->RunsTasksOnCurrentThread());
144 160
145 if (!encoder_active_) 161 if (!encoder_active_)
146 return; 162 return;
miu 2016/04/30 00:41:14 There are a bunch of early returns in this method.
xjz 2016/05/03 01:17:59 Done. 1. Put all the necessary early return operat
147 163
164 DCHECK(!free_input_buffer_index_.empty());
165
148 in_progress_frame_encodes_.push_back(InProgressFrameEncode( 166 in_progress_frame_encodes_.push_back(InProgressFrameEncode(
149 video_frame, reference_time, frame_encoded_callback, 167 video_frame, reference_time, frame_encoded_callback,
150 requested_bit_rate_)); 168 requested_bit_rate_));
151 169
170 scoped_refptr<media::VideoFrame> frame = video_frame;
171 if (video_frame->coded_size() != frame_coded_size_) {
172 DCHECK_GE(frame_coded_size_.width(), video_frame->visible_rect().width());
173 DCHECK_GE(frame_coded_size_.height(),
174 video_frame->visible_rect().height());
175
176 int index = free_input_buffer_index_.back();
177 base::SharedMemory* input_buffer = input_buffers_[index];
178 frame = VideoFrame::WrapExternalSharedMemory(
179 video_frame->format(), frame_coded_size_, video_frame->visible_rect(),
180 video_frame->visible_rect().size(),
181 static_cast<uint8_t*>(input_buffer->memory()),
182 input_buffer->mapped_size(), input_buffer->handle(), 0,
183 video_frame->timestamp());
184 if (!frame.get()) {
185 VLOG(1) << "Error: ExternalVideoEncoder: CreateFrame failed.";
miu 2016/04/30 00:41:14 This should probably be LOG(DFATAL) since either t
xjz 2016/05/03 01:17:59 Done.
186 return;
187 }
188
189 // Copy the input frame to match the input requirements for the encoder.
190 if (!media::I420CopyWithPadding(video_frame, frame)) {
191 VLOG(1) << "ERROR: ExternalVideoEncoder: Copy failed.";
miu 2016/04/30 00:41:14 ditto: LOG(DFATAL).
xjz 2016/05/03 01:17:59 Done. Combined this check with the above check on
192 return;
193 }
194
195 frame->AddDestructionObserver(media::BindToCurrentLoop(
196 base::Bind(&ExternalVideoEncoder::VEAClientImpl::OnFinishEncodeFrame,
197 this, index)));
198 free_input_buffer_index_.pop_back();
199 }
200
152 // BitstreamBufferReady will be called once the encoder is done. 201 // BitstreamBufferReady will be called once the encoder is done.
153 video_encode_accelerator_->Encode(video_frame, key_frame_requested); 202 video_encode_accelerator_->Encode(frame, key_frame_requested);
154 } 203 }
155 204
205 // Return true if there is available input buffer.
206 bool IsInputBufferReady() { return !free_input_buffer_index_.empty(); }
207
156 protected: 208 protected:
157 void NotifyError(VideoEncodeAccelerator::Error error) final { 209 void NotifyError(VideoEncodeAccelerator::Error error) final {
158 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 210 DCHECK(task_runner_->RunsTasksOnCurrentThread());
159 211
160 DCHECK(error != VideoEncodeAccelerator::kInvalidArgumentError && 212 DCHECK(error != VideoEncodeAccelerator::kInvalidArgumentError &&
161 error != VideoEncodeAccelerator::kIllegalStateError); 213 error != VideoEncodeAccelerator::kIllegalStateError);
162 214
163 encoder_active_ = false; 215 encoder_active_ = false;
164 216
165 cast_environment_->PostTask( 217 cast_environment_->PostTask(
166 CastEnvironment::MAIN, 218 CastEnvironment::MAIN,
167 FROM_HERE, 219 FROM_HERE,
168 base::Bind(status_change_cb_, STATUS_CODEC_RUNTIME_ERROR)); 220 base::Bind(status_change_cb_, STATUS_CODEC_RUNTIME_ERROR));
169 221
170 // TODO(miu): Force-flush all |in_progress_frame_encodes_| immediately so 222 // TODO(miu): Force-flush all |in_progress_frame_encodes_| immediately so
171 // pending frames do not become stuck, freezing VideoSender. 223 // pending frames do not become stuck, freezing VideoSender.
172 } 224 }
173 225
174 // Called to allocate the input and output buffers. 226 // Called to allocate the input and output buffers.
175 void RequireBitstreamBuffers(unsigned int input_count, 227 void RequireBitstreamBuffers(unsigned int input_count,
176 const gfx::Size& input_coded_size, 228 const gfx::Size& input_coded_size,
177 size_t output_buffer_size) final { 229 size_t output_buffer_size) final {
178 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 230 DCHECK(task_runner_->RunsTasksOnCurrentThread());
179 231
180 // TODO(miu): Investigate why we are ignoring |input_count| (4) and instead 232 frame_coded_size_ = input_coded_size;
181 // using |kOutputBufferCount| (3) here. 233
234 for (size_t j = 0; j < input_count + kExtraInputBufferCount; ++j) {
miu 2016/04/30 00:41:14 Instead of allocating these up-front, can we alloc
xjz 2016/05/03 01:17:59 Done.
235 create_video_encode_memory_cb_.Run(
236 media::VideoFrame::AllocationSize(media::PIXEL_FORMAT_I420,
237 input_coded_size),
238 base::Bind(&VEAClientImpl::OnCreateInputSharedMemory, this));
239 }
240
182 for (size_t j = 0; j < kOutputBufferCount; ++j) { 241 for (size_t j = 0; j < kOutputBufferCount; ++j) {
183 create_video_encode_memory_cb_.Run( 242 create_video_encode_memory_cb_.Run(
184 output_buffer_size, 243 output_buffer_size,
185 base::Bind(&VEAClientImpl::OnCreateSharedMemory, this)); 244 base::Bind(&VEAClientImpl::OnCreateSharedMemory, this));
186 } 245 }
187 } 246 }
188 247
189 // Encoder has encoded a frame and it's available in one of the output 248 // Encoder has encoded a frame and it's available in one of the output
190 // buffers. Package the result in a media::cast::EncodedFrame and post it 249 // buffers. Package the result in a media::cast::EncodedFrame and post it
191 // to the Cast MAIN thread via the supplied callback. 250 // to the Cast MAIN thread via the supplied callback.
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 } 420 }
362 421
363 // Note: This method can be called on any thread. 422 // Note: This method can be called on any thread.
364 void OnCreateSharedMemory(scoped_ptr<base::SharedMemory> memory) { 423 void OnCreateSharedMemory(scoped_ptr<base::SharedMemory> memory) {
365 task_runner_->PostTask(FROM_HERE, 424 task_runner_->PostTask(FROM_HERE,
366 base::Bind(&VEAClientImpl::OnReceivedSharedMemory, 425 base::Bind(&VEAClientImpl::OnReceivedSharedMemory,
367 this, 426 this,
368 base::Passed(&memory))); 427 base::Passed(&memory)));
369 } 428 }
370 429
430 void OnCreateInputSharedMemory(scoped_ptr<base::SharedMemory> memory) {
431 task_runner_->PostTask(
432 FROM_HERE, base::Bind(&VEAClientImpl::OnReceivedInputSharedMemory, this,
433 base::Passed(&memory)));
434 }
435
371 void OnReceivedSharedMemory(scoped_ptr<base::SharedMemory> memory) { 436 void OnReceivedSharedMemory(scoped_ptr<base::SharedMemory> memory) {
372 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 437 DCHECK(task_runner_->RunsTasksOnCurrentThread());
373 438
374 output_buffers_.push_back(std::move(memory)); 439 output_buffers_.push_back(std::move(memory));
375 440
376 // Wait until all requested buffers are received. 441 // Wait until all requested buffers are received.
377 if (output_buffers_.size() < kOutputBufferCount) 442 if (output_buffers_.size() < kOutputBufferCount)
378 return; 443 return;
379 444
380 // Immediately provide all output buffers to the VEA. 445 // Immediately provide all output buffers to the VEA.
381 for (size_t i = 0; i < output_buffers_.size(); ++i) { 446 for (size_t i = 0; i < output_buffers_.size(); ++i) {
382 video_encode_accelerator_->UseOutputBitstreamBuffer( 447 video_encode_accelerator_->UseOutputBitstreamBuffer(
383 media::BitstreamBuffer(static_cast<int32_t>(i), 448 media::BitstreamBuffer(static_cast<int32_t>(i),
384 output_buffers_[i]->handle(), 449 output_buffers_[i]->handle(),
385 output_buffers_[i]->mapped_size())); 450 output_buffers_[i]->mapped_size()));
386 } 451 }
387 } 452 }
388 453
454 void OnReceivedInputSharedMemory(scoped_ptr<base::SharedMemory> memory) {
455 DCHECK(task_runner_->RunsTasksOnCurrentThread());
456
457 input_buffers_.push_back(std::move(memory));
458 free_input_buffer_index_.push_back(input_buffers_.size() - 1);
459 }
460
389 // Parse H264 SPS, PPS, and Slice header, and return the averaged frame 461 // Parse H264 SPS, PPS, and Slice header, and return the averaged frame
390 // quantizer in the range of [0, 51], or -1 on parse error. 462 // quantizer in the range of [0, 51], or -1 on parse error.
391 double GetH264FrameQuantizer(const uint8_t* encoded_data, off_t size) { 463 double GetH264FrameQuantizer(const uint8_t* encoded_data, off_t size) {
392 DCHECK(encoded_data); 464 DCHECK(encoded_data);
393 if (!size) 465 if (!size)
394 return -1; 466 return -1;
395 h264_parser_.SetStream(encoded_data, size); 467 h264_parser_.SetStream(encoded_data, size);
396 double total_quantizer = 0; 468 double total_quantizer = 0;
397 int num_slices = 0; 469 int num_slices = 0;
398 470
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
455 uint32_t next_frame_id_; 527 uint32_t next_frame_id_;
456 bool key_frame_encountered_; 528 bool key_frame_encountered_;
457 std::string stream_header_; 529 std::string stream_header_;
458 VideoCodecProfile codec_profile_; 530 VideoCodecProfile codec_profile_;
459 bool key_frame_quantizer_parsable_; 531 bool key_frame_quantizer_parsable_;
460 H264Parser h264_parser_; 532 H264Parser h264_parser_;
461 533
462 // Shared memory buffers for output with the VideoAccelerator. 534 // Shared memory buffers for output with the VideoAccelerator.
463 ScopedVector<base::SharedMemory> output_buffers_; 535 ScopedVector<base::SharedMemory> output_buffers_;
464 536
537 // Shared memory buffers for input video frames with the VideoAccelerator.
538 ScopedVector<base::SharedMemory> input_buffers_;
miu 2016/04/30 00:41:14 ScopedVector is deprecated. Please use std::vector
xjz 2016/05/03 01:17:59 Done.
539
540 // Available input buffer index. These buffers are used in FILO order.
541 std::vector<int> free_input_buffer_index_;
542
465 // FIFO list. 543 // FIFO list.
466 std::list<InProgressFrameEncode> in_progress_frame_encodes_; 544 std::list<InProgressFrameEncode> in_progress_frame_encodes_;
467 545
468 // The requested encode bit rate for the next frame. 546 // The requested encode bit rate for the next frame.
469 int requested_bit_rate_; 547 int requested_bit_rate_;
470 548
471 // Used to compute utilization metrics for each frame. 549 // Used to compute utilization metrics for each frame.
472 QuantizerEstimator quantizer_estimator_; 550 QuantizerEstimator quantizer_estimator_;
473 551
474 // Set to true once a frame with zero-length encoded data has been 552 // Set to true once a frame with zero-length encoded data has been
475 // encountered. 553 // encountered.
476 // TODO(miu): Remove after discovering cause. http://crbug.com/519022 554 // TODO(miu): Remove after discovering cause. http://crbug.com/519022
477 bool has_seen_zero_length_encoded_frame_; 555 bool has_seen_zero_length_encoded_frame_;
478 556
557 // The coded size of the video frame required by Encoder. This size is
558 // obtained from VEA through |RequireBitstreamBuffers()|.
559 gfx::Size frame_coded_size_;
560
479 DISALLOW_COPY_AND_ASSIGN(VEAClientImpl); 561 DISALLOW_COPY_AND_ASSIGN(VEAClientImpl);
480 }; 562 };
481 563
482 // static 564 // static
483 bool ExternalVideoEncoder::IsSupported(const VideoSenderConfig& video_config) { 565 bool ExternalVideoEncoder::IsSupported(const VideoSenderConfig& video_config) {
484 if (video_config.codec != CODEC_VIDEO_VP8 && 566 if (video_config.codec != CODEC_VIDEO_VP8 &&
485 video_config.codec != CODEC_VIDEO_H264) 567 video_config.codec != CODEC_VIDEO_H264)
486 return false; 568 return false;
487 569
488 // TODO(miu): "Layering hooks" are needed to be able to query outside of 570 // TODO(miu): "Layering hooks" are needed to be able to query outside of
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 bool ExternalVideoEncoder::EncodeVideoFrame( 610 bool ExternalVideoEncoder::EncodeVideoFrame(
529 const scoped_refptr<media::VideoFrame>& video_frame, 611 const scoped_refptr<media::VideoFrame>& video_frame,
530 const base::TimeTicks& reference_time, 612 const base::TimeTicks& reference_time,
531 const FrameEncodedCallback& frame_encoded_callback) { 613 const FrameEncodedCallback& frame_encoded_callback) {
532 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 614 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
533 DCHECK(!frame_encoded_callback.is_null()); 615 DCHECK(!frame_encoded_callback.is_null());
534 616
535 if (!client_ || video_frame->visible_rect().size() != frame_size_) 617 if (!client_ || video_frame->visible_rect().size() != frame_size_)
536 return false; 618 return false;
537 619
620 // Drop frame until an input buffer is available.
621 if (!client_->IsInputBufferReady())
miu 2016/04/30 00:41:14 See comments above. If input buffers are allocated
xjz 2016/05/03 01:17:59 Removed. The purpose of using this was actually tr
622 return false;
623
538 client_->task_runner()->PostTask(FROM_HERE, 624 client_->task_runner()->PostTask(FROM_HERE,
539 base::Bind(&VEAClientImpl::EncodeVideoFrame, 625 base::Bind(&VEAClientImpl::EncodeVideoFrame,
540 client_, 626 client_,
541 video_frame, 627 video_frame,
542 reference_time, 628 reference_time,
543 key_frame_requested_, 629 key_frame_requested_,
544 frame_encoded_callback)); 630 frame_encoded_callback));
545 key_frame_requested_ = false; 631 key_frame_requested_ = false;
546 return true; 632 return true;
547 } 633 }
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
787 const double kEntropyAtMaxQuantizer = 7.5; 873 const double kEntropyAtMaxQuantizer = 7.5;
788 const double slope = 874 const double slope =
789 (MAX_VP8_QUANTIZER - MIN_VP8_QUANTIZER) / kEntropyAtMaxQuantizer; 875 (MAX_VP8_QUANTIZER - MIN_VP8_QUANTIZER) / kEntropyAtMaxQuantizer;
790 const double quantizer = std::min<double>( 876 const double quantizer = std::min<double>(
791 MAX_VP8_QUANTIZER, MIN_VP8_QUANTIZER + slope * shannon_entropy); 877 MAX_VP8_QUANTIZER, MIN_VP8_QUANTIZER + slope * shannon_entropy);
792 return quantizer; 878 return quantizer;
793 } 879 }
794 880
795 } // namespace cast 881 } // namespace cast
796 } // namespace media 882 } // namespace media
OLDNEW
« media/base/video_util.cc ('K') | « media/base/video_util.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698