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 <cmath> | 7 #include <cmath> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 11 matching lines...) Expand all Loading... | |
22 #include "media/base/video_frame.h" | 22 #include "media/base/video_frame.h" |
23 #include "media/base/video_types.h" | 23 #include "media/base/video_types.h" |
24 #include "media/base/video_util.h" | 24 #include "media/base/video_util.h" |
25 #include "media/cast/cast_config.h" | 25 #include "media/cast/cast_config.h" |
26 #include "media/cast/cast_defines.h" | 26 #include "media/cast/cast_defines.h" |
27 #include "media/cast/common/rtp_time.h" | 27 #include "media/cast/common/rtp_time.h" |
28 #include "media/cast/logging/logging_defines.h" | 28 #include "media/cast/logging/logging_defines.h" |
29 #include "media/cast/net/cast_transport_config.h" | 29 #include "media/cast/net/cast_transport_config.h" |
30 #include "media/cast/sender/vp8_quantizer_parser.h" | 30 #include "media/cast/sender/vp8_quantizer_parser.h" |
31 #include "media/filters/h264_parser.h" | 31 #include "media/filters/h264_parser.h" |
32 #include "third_party/libyuv/include/libyuv.h" | |
32 | 33 |
33 namespace { | 34 namespace { |
34 | 35 |
35 enum { MAX_H264_QUANTIZER = 51 }; | 36 enum { MAX_H264_QUANTIZER = 51 }; |
36 static const size_t kOutputBufferCount = 3; | 37 static const size_t kOutputBufferCount = 3; |
37 | 38 |
38 } // namespace | 39 } // namespace |
39 | 40 |
40 namespace media { | 41 namespace media { |
41 namespace cast { | 42 namespace cast { |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
142 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) { | 143 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) { |
143 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 144 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
144 | 145 |
145 if (!encoder_active_) | 146 if (!encoder_active_) |
146 return; | 147 return; |
147 | 148 |
148 in_progress_frame_encodes_.push_back(InProgressFrameEncode( | 149 in_progress_frame_encodes_.push_back(InProgressFrameEncode( |
149 video_frame, reference_time, frame_encoded_callback, | 150 video_frame, reference_time, frame_encoded_callback, |
150 requested_bit_rate_)); | 151 requested_bit_rate_)); |
151 | 152 |
153 scoped_refptr<media::VideoFrame> frame = video_frame; | |
154 if (video_frame->coded_size() != frame_coded_size_) { | |
miu
2016/04/26 19:20:17
For safety, we should probably:
DCHECK_GE(frame
xjz
2016/04/27 22:13:54
Done.
| |
155 frame = VideoFrame::CreateZeroInitializedFrame( | |
156 video_frame->format(), frame_coded_size_, video_frame->visible_rect(), | |
157 video_frame->natural_size(), video_frame->timestamp()); | |
158 if (!frame.get()) { | |
159 VLOG(1) << "Error: ExternalVideoEncoder: CreateFrame failed."; | |
160 return; | |
161 } | |
162 | |
163 // Copy the input frame to match the input requirements for the encoder. | |
164 if (libyuv::I420Copy(video_frame->data(media::VideoFrame::kYPlane), | |
165 video_frame->stride(media::VideoFrame::kYPlane), | |
166 video_frame->data(media::VideoFrame::kUPlane), | |
167 video_frame->stride(media::VideoFrame::kUPlane), | |
168 video_frame->data(media::VideoFrame::kVPlane), | |
169 video_frame->stride(media::VideoFrame::kVPlane), | |
170 frame->data(media::VideoFrame::kYPlane), | |
171 frame->stride(media::VideoFrame::kYPlane), | |
172 frame->data(media::VideoFrame::kUPlane), | |
173 frame->stride(media::VideoFrame::kUPlane), | |
174 frame->data(media::VideoFrame::kVPlane), | |
175 frame->stride(media::VideoFrame::kVPlane), | |
176 video_frame->visible_rect().width(), | |
177 video_frame->visible_rect().height())) { | |
178 VLOG(1) << "ERROR: ExternalVideoEncoder: Copy failed."; | |
179 return; | |
180 } | |
181 } | |
182 | |
152 // BitstreamBufferReady will be called once the encoder is done. | 183 // BitstreamBufferReady will be called once the encoder is done. |
153 video_encode_accelerator_->Encode(video_frame, key_frame_requested); | 184 video_encode_accelerator_->Encode(frame, key_frame_requested); |
154 } | 185 } |
155 | 186 |
156 protected: | 187 protected: |
157 void NotifyError(VideoEncodeAccelerator::Error error) final { | 188 void NotifyError(VideoEncodeAccelerator::Error error) final { |
158 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 189 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
159 | 190 |
160 DCHECK(error != VideoEncodeAccelerator::kInvalidArgumentError && | 191 DCHECK(error != VideoEncodeAccelerator::kInvalidArgumentError && |
161 error != VideoEncodeAccelerator::kIllegalStateError); | 192 error != VideoEncodeAccelerator::kIllegalStateError); |
162 | 193 |
163 encoder_active_ = false; | 194 encoder_active_ = false; |
164 | 195 |
165 cast_environment_->PostTask( | 196 cast_environment_->PostTask( |
166 CastEnvironment::MAIN, | 197 CastEnvironment::MAIN, |
167 FROM_HERE, | 198 FROM_HERE, |
168 base::Bind(status_change_cb_, STATUS_CODEC_RUNTIME_ERROR)); | 199 base::Bind(status_change_cb_, STATUS_CODEC_RUNTIME_ERROR)); |
169 | 200 |
170 // TODO(miu): Force-flush all |in_progress_frame_encodes_| immediately so | 201 // TODO(miu): Force-flush all |in_progress_frame_encodes_| immediately so |
171 // pending frames do not become stuck, freezing VideoSender. | 202 // pending frames do not become stuck, freezing VideoSender. |
172 } | 203 } |
173 | 204 |
174 // Called to allocate the input and output buffers. | 205 // Called to allocate the input and output buffers. |
175 void RequireBitstreamBuffers(unsigned int input_count, | 206 void RequireBitstreamBuffers(unsigned int input_count, |
176 const gfx::Size& input_coded_size, | 207 const gfx::Size& input_coded_size, |
177 size_t output_buffer_size) final { | 208 size_t output_buffer_size) final { |
178 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 209 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
179 | 210 |
180 // TODO(miu): Investigate why we are ignoring |input_count| (4) and instead | 211 frame_coded_size_ = input_coded_size; |
181 // using |kOutputBufferCount| (3) here. | 212 |
182 for (size_t j = 0; j < kOutputBufferCount; ++j) { | 213 for (size_t j = 0; j < kOutputBufferCount; ++j) { |
183 create_video_encode_memory_cb_.Run( | 214 create_video_encode_memory_cb_.Run( |
184 output_buffer_size, | 215 output_buffer_size, |
185 base::Bind(&VEAClientImpl::OnCreateSharedMemory, this)); | 216 base::Bind(&VEAClientImpl::OnCreateSharedMemory, this)); |
186 } | 217 } |
187 } | 218 } |
188 | 219 |
189 // Encoder has encoded a frame and it's available in one of the output | 220 // 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 | 221 // buffers. Package the result in a media::cast::EncodedFrame and post it |
191 // to the Cast MAIN thread via the supplied callback. | 222 // to the Cast MAIN thread via the supplied callback. |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
469 int requested_bit_rate_; | 500 int requested_bit_rate_; |
470 | 501 |
471 // Used to compute utilization metrics for each frame. | 502 // Used to compute utilization metrics for each frame. |
472 QuantizerEstimator quantizer_estimator_; | 503 QuantizerEstimator quantizer_estimator_; |
473 | 504 |
474 // Set to true once a frame with zero-length encoded data has been | 505 // Set to true once a frame with zero-length encoded data has been |
475 // encountered. | 506 // encountered. |
476 // TODO(miu): Remove after discovering cause. http://crbug.com/519022 | 507 // TODO(miu): Remove after discovering cause. http://crbug.com/519022 |
477 bool has_seen_zero_length_encoded_frame_; | 508 bool has_seen_zero_length_encoded_frame_; |
478 | 509 |
510 // The coded size of the video frame required by Encoder. This size is | |
511 // obtained from VEA through |RequireBitstreamBuffers()|. | |
512 gfx::Size frame_coded_size_; | |
513 | |
479 DISALLOW_COPY_AND_ASSIGN(VEAClientImpl); | 514 DISALLOW_COPY_AND_ASSIGN(VEAClientImpl); |
480 }; | 515 }; |
481 | 516 |
482 // static | 517 // static |
483 bool ExternalVideoEncoder::IsSupported(const VideoSenderConfig& video_config) { | 518 bool ExternalVideoEncoder::IsSupported(const VideoSenderConfig& video_config) { |
484 if (video_config.codec != CODEC_VIDEO_VP8 && | 519 if (video_config.codec != CODEC_VIDEO_VP8 && |
485 video_config.codec != CODEC_VIDEO_H264) | 520 video_config.codec != CODEC_VIDEO_H264) |
486 return false; | 521 return false; |
487 | 522 |
488 // TODO(miu): "Layering hooks" are needed to be able to query outside of | 523 // TODO(miu): "Layering hooks" are needed to be able to query outside of |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
787 const double kEntropyAtMaxQuantizer = 7.5; | 822 const double kEntropyAtMaxQuantizer = 7.5; |
788 const double slope = | 823 const double slope = |
789 (MAX_VP8_QUANTIZER - MIN_VP8_QUANTIZER) / kEntropyAtMaxQuantizer; | 824 (MAX_VP8_QUANTIZER - MIN_VP8_QUANTIZER) / kEntropyAtMaxQuantizer; |
790 const double quantizer = std::min<double>( | 825 const double quantizer = std::min<double>( |
791 MAX_VP8_QUANTIZER, MIN_VP8_QUANTIZER + slope * shannon_entropy); | 826 MAX_VP8_QUANTIZER, MIN_VP8_QUANTIZER + slope * shannon_entropy); |
792 return quantizer; | 827 return quantizer; |
793 } | 828 } |
794 | 829 |
795 } // namespace cast | 830 } // namespace cast |
796 } // namespace media | 831 } // namespace media |
OLD | NEW |