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

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: 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
« no previous file with comments | « no previous file | 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"
(...skipping 17 matching lines...) Expand all
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 32
33 namespace { 33 namespace {
34 34
35 enum { MAX_H264_QUANTIZER = 51 }; 35 enum { MAX_H264_QUANTIZER = 51 };
36 static const size_t kOutputBufferCount = 3; 36 static const size_t kOutputBufferCount = 3;
37 37
38 // Copy buffer to match the required coded size.
39 // Cropping or padding is done as required.
40 bool StridedBufferCopy(const uint8_t* src,
41 const gfx::Size& visible_rect,
42 int src_stride,
43 uint8_t* dst,
44 const gfx::Size& dst_coded_size) {
45 if (!src || !dst)
46 return false;
47
48 const int src_width = visible_rect.width();
49 const int src_height = visible_rect.height();
50 const int dst_stride = dst_coded_size.width();
51 const int dst_height = dst_coded_size.height();
52 const int copy_width = src_width < dst_stride ? src_width : dst_stride;
53 const int copy_height = src_height < dst_height ? src_height : dst_height;
54
55 for (int i = 0; i < copy_height; ++i) {
56 std::memcpy(dst, src, copy_width);
57 // Padding the remaining columns by repeating the last column of the source.
58 if (copy_width < dst_stride)
59 std::memset(dst + copy_width, src[copy_width - 1],
60 dst_stride - copy_width);
61 src += src_stride;
62 dst += dst_stride;
63 }
64
65 // Padding the remaining rows by repeating the last row of the source.
66 src = dst - dst_stride;
67 for (int i = copy_height; i < dst_height; ++i) {
68 memcpy(dst, src, dst_stride);
69 dst += dst_stride;
70 }
71
72 return true;
73 }
74
75 // Copy video frame to match the required coded size.
76 bool StridedFrameCopy(const scoped_refptr<media::VideoFrame> src_frame,
miu 2016/04/25 23:39:39 Oh! Oops, I forgot to mention these routines alre
xjz 2016/04/26 17:42:30 Done. Added dependency on libyuv. This copy does n
miu 2016/04/26 19:20:17 Oh. IMO, the padding was a nice thing to have. A
xjz 2016/04/27 22:13:54 Done. Padding is nice to improve coding efficiency
77 scoped_refptr<media::VideoFrame> dst_frame) {
78 if (!StridedBufferCopy(src_frame->data(media::VideoFrame::kYPlane),
79 src_frame->visible_rect().size(),
80 src_frame->stride(media::VideoFrame::kYPlane),
81 dst_frame->data(media::VideoFrame::kYPlane),
82 dst_frame->coded_size()))
83 return false;
84
85 const gfx::Size uv_visible_size(src_frame->visible_rect().width() / 2,
86 src_frame->visible_rect().height() / 2);
87 const gfx::Size uv_coded_size(dst_frame->coded_size().width() / 2,
88 dst_frame->coded_size().height() / 2);
89 if (!StridedBufferCopy(
90 src_frame->data(media::VideoFrame::kUPlane), uv_visible_size,
91 src_frame->stride(media::VideoFrame::kUPlane),
92 dst_frame->data(media::VideoFrame::kUPlane), uv_coded_size))
93 return false;
94
95 if (!StridedBufferCopy(
96 src_frame->data(media::VideoFrame::kVPlane), uv_visible_size,
97 src_frame->stride(media::VideoFrame::kVPlane),
98 dst_frame->data(media::VideoFrame::kVPlane), uv_coded_size))
99 return false;
100
101 return true;
102 }
103
38 } // namespace 104 } // namespace
39 105
40 namespace media { 106 namespace media {
41 namespace cast { 107 namespace cast {
42 108
43 // Container for the associated data of a video frame being processed. 109 // Container for the associated data of a video frame being processed.
44 struct InProgressFrameEncode { 110 struct InProgressFrameEncode {
45 // The source content to encode. 111 // The source content to encode.
46 const scoped_refptr<VideoFrame> video_frame; 112 const scoped_refptr<VideoFrame> video_frame;
47 113
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) { 208 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) {
143 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 209 DCHECK(task_runner_->RunsTasksOnCurrentThread());
144 210
145 if (!encoder_active_) 211 if (!encoder_active_)
146 return; 212 return;
147 213
148 in_progress_frame_encodes_.push_back(InProgressFrameEncode( 214 in_progress_frame_encodes_.push_back(InProgressFrameEncode(
149 video_frame, reference_time, frame_encoded_callback, 215 video_frame, reference_time, frame_encoded_callback,
150 requested_bit_rate_)); 216 requested_bit_rate_));
151 217
218 scoped_refptr<media::VideoFrame> frame = video_frame;
219 if (video_frame->coded_size() != frame_coded_size_) {
220 VLOG(1) << "ExternalVideoEncoder copy required. "
miu 2016/04/25 23:39:39 nit: Maybe make these logging statements VLOG(2) s
xjz 2016/04/26 17:42:30 Removed this log.
221 << "Source coded size: " << video_frame->coded_size().ToString()
222 << " Required coded size: " << frame_coded_size_.ToString();
223
224 frame = VideoFrame::CreateFrame(
225 video_frame->format(), frame_coded_size_, video_frame->visible_rect(),
226 video_frame->natural_size(), video_frame->timestamp());
227 if (!frame.get()) {
228 VLOG(1) << "Error: ExternalVideoEncoder: CreateFrame failed.";
229 return;
230 }
231
232 // Copy the input frame to match the input requirements for the encoder.
233 if (!StridedFrameCopy(video_frame, frame)) {
234 VLOG(1) << "ERROR: ExternalVideoEncoder: Copy failed.";
235 return;
236 }
237 }
238
152 // BitstreamBufferReady will be called once the encoder is done. 239 // BitstreamBufferReady will be called once the encoder is done.
153 video_encode_accelerator_->Encode(video_frame, key_frame_requested); 240 video_encode_accelerator_->Encode(frame, key_frame_requested);
154 } 241 }
155 242
156 protected: 243 protected:
157 void NotifyError(VideoEncodeAccelerator::Error error) final { 244 void NotifyError(VideoEncodeAccelerator::Error error) final {
158 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 245 DCHECK(task_runner_->RunsTasksOnCurrentThread());
159 246
160 DCHECK(error != VideoEncodeAccelerator::kInvalidArgumentError && 247 DCHECK(error != VideoEncodeAccelerator::kInvalidArgumentError &&
161 error != VideoEncodeAccelerator::kIllegalStateError); 248 error != VideoEncodeAccelerator::kIllegalStateError);
162 249
163 encoder_active_ = false; 250 encoder_active_ = false;
164 251
165 cast_environment_->PostTask( 252 cast_environment_->PostTask(
166 CastEnvironment::MAIN, 253 CastEnvironment::MAIN,
167 FROM_HERE, 254 FROM_HERE,
168 base::Bind(status_change_cb_, STATUS_CODEC_RUNTIME_ERROR)); 255 base::Bind(status_change_cb_, STATUS_CODEC_RUNTIME_ERROR));
169 256
170 // TODO(miu): Force-flush all |in_progress_frame_encodes_| immediately so 257 // TODO(miu): Force-flush all |in_progress_frame_encodes_| immediately so
171 // pending frames do not become stuck, freezing VideoSender. 258 // pending frames do not become stuck, freezing VideoSender.
172 } 259 }
173 260
174 // Called to allocate the input and output buffers. 261 // Called to allocate the input and output buffers.
175 void RequireBitstreamBuffers(unsigned int input_count, 262 void RequireBitstreamBuffers(unsigned int input_count,
176 const gfx::Size& input_coded_size, 263 const gfx::Size& input_coded_size,
177 size_t output_buffer_size) final { 264 size_t output_buffer_size) final {
178 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 265 DCHECK(task_runner_->RunsTasksOnCurrentThread());
179 266
267 frame_coded_size_ = input_coded_size;
268
180 // TODO(miu): Investigate why we are ignoring |input_count| (4) and instead 269 // TODO(miu): Investigate why we are ignoring |input_count| (4) and instead
181 // using |kOutputBufferCount| (3) here. 270 // using |kOutputBufferCount| (3) here.
182 for (size_t j = 0; j < kOutputBufferCount; ++j) { 271 for (size_t j = 0; j < kOutputBufferCount; ++j) {
miu 2016/04/25 23:39:39 BTW--In a follow-up change, perhaps you could take
xjz 2016/04/26 17:42:30 |input_count| is how many frames the encoder will
183 create_video_encode_memory_cb_.Run( 272 create_video_encode_memory_cb_.Run(
184 output_buffer_size, 273 output_buffer_size,
185 base::Bind(&VEAClientImpl::OnCreateSharedMemory, this)); 274 base::Bind(&VEAClientImpl::OnCreateSharedMemory, this));
186 } 275 }
187 } 276 }
188 277
189 // Encoder has encoded a frame and it's available in one of the output 278 // 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 279 // buffers. Package the result in a media::cast::EncodedFrame and post it
191 // to the Cast MAIN thread via the supplied callback. 280 // to the Cast MAIN thread via the supplied callback.
192 void BitstreamBufferReady(int32_t bitstream_buffer_id, 281 void BitstreamBufferReady(int32_t bitstream_buffer_id,
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
469 int requested_bit_rate_; 558 int requested_bit_rate_;
470 559
471 // Used to compute utilization metrics for each frame. 560 // Used to compute utilization metrics for each frame.
472 QuantizerEstimator quantizer_estimator_; 561 QuantizerEstimator quantizer_estimator_;
473 562
474 // Set to true once a frame with zero-length encoded data has been 563 // Set to true once a frame with zero-length encoded data has been
475 // encountered. 564 // encountered.
476 // TODO(miu): Remove after discovering cause. http://crbug.com/519022 565 // TODO(miu): Remove after discovering cause. http://crbug.com/519022
477 bool has_seen_zero_length_encoded_frame_; 566 bool has_seen_zero_length_encoded_frame_;
478 567
568 // The coded size of the video frame required by Encoder. This size is
569 // obtained from VEA through |RequireBitstreamBuffers()|.
570 gfx::Size frame_coded_size_;
571
479 DISALLOW_COPY_AND_ASSIGN(VEAClientImpl); 572 DISALLOW_COPY_AND_ASSIGN(VEAClientImpl);
480 }; 573 };
481 574
482 // static 575 // static
483 bool ExternalVideoEncoder::IsSupported(const VideoSenderConfig& video_config) { 576 bool ExternalVideoEncoder::IsSupported(const VideoSenderConfig& video_config) {
484 if (video_config.codec != CODEC_VIDEO_VP8 && 577 if (video_config.codec != CODEC_VIDEO_VP8 &&
485 video_config.codec != CODEC_VIDEO_H264) 578 video_config.codec != CODEC_VIDEO_H264)
486 return false; 579 return false;
487 580
488 // TODO(miu): "Layering hooks" are needed to be able to query outside of 581 // 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
787 const double kEntropyAtMaxQuantizer = 7.5; 880 const double kEntropyAtMaxQuantizer = 7.5;
788 const double slope = 881 const double slope =
789 (MAX_VP8_QUANTIZER - MIN_VP8_QUANTIZER) / kEntropyAtMaxQuantizer; 882 (MAX_VP8_QUANTIZER - MIN_VP8_QUANTIZER) / kEntropyAtMaxQuantizer;
790 const double quantizer = std::min<double>( 883 const double quantizer = std::min<double>(
791 MAX_VP8_QUANTIZER, MIN_VP8_QUANTIZER + slope * shannon_entropy); 884 MAX_VP8_QUANTIZER, MIN_VP8_QUANTIZER + slope * shannon_entropy);
792 return quantizer; 885 return quantizer;
793 } 886 }
794 887
795 } // namespace cast 888 } // namespace cast
796 } // namespace media 889 } // namespace media
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698