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

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

Issue 1955233002: Revert of 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
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/shared_memory.h" 17 #include "base/memory/shared_memory.h"
17 #include "base/message_loop/message_loop.h" 18 #include "base/message_loop/message_loop.h"
18 #include "base/metrics/histogram.h" 19 #include "base/metrics/histogram.h"
19 #include "base/strings/stringprintf.h" 20 #include "base/strings/stringprintf.h"
20 #include "build/build_config.h" 21 #include "build/build_config.h"
21 #include "media/base/bind_to_current_loop.h"
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/common/rtp_time.h" 26 #include "media/cast/common/rtp_time.h"
27 #include "media/cast/logging/logging_defines.h" 27 #include "media/cast/logging/logging_defines.h"
28 #include "media/cast/net/cast_transport_config.h" 28 #include "media/cast/net/cast_transport_config.h"
29 #include "media/cast/sender/vp8_quantizer_parser.h" 29 #include "media/cast/sender/vp8_quantizer_parser.h"
30 #include "media/filters/h264_parser.h" 30 #include "media/filters/h264_parser.h"
31 31
32 namespace { 32 namespace {
33 33
34 enum { MAX_H264_QUANTIZER = 51 }; 34 enum { MAX_H264_QUANTIZER = 51 };
35 35 static const size_t kOutputBufferCount = 3;
36 // Number of buffers for encoded bit stream.
37 constexpr size_t kOutputBufferCount = 3;
38
39 // Maximum number of extra input buffers for encoder. The input buffers are only
40 // used when copy is needed to match the required coded size.
41 constexpr size_t kExtraInputBufferCount = 2;
42 36
43 } // namespace 37 } // namespace
44 38
45 namespace media { 39 namespace media {
46 namespace cast { 40 namespace cast {
47 41
48 // Container for the associated data of a video frame being processed. 42 // Container for the associated data of a video frame being processed.
49 struct InProgressFrameEncode { 43 struct InProgressFrameEncode {
50 // The source content to encode. 44 // The source content to encode.
51 const scoped_refptr<VideoFrame> video_frame; 45 const scoped_refptr<VideoFrame> video_frame;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 max_frame_rate_(max_frame_rate), 89 max_frame_rate_(max_frame_rate),
96 status_change_cb_(status_change_cb), 90 status_change_cb_(status_change_cb),
97 create_video_encode_memory_cb_(create_video_encode_memory_cb), 91 create_video_encode_memory_cb_(create_video_encode_memory_cb),
98 video_encode_accelerator_(std::move(vea)), 92 video_encode_accelerator_(std::move(vea)),
99 encoder_active_(false), 93 encoder_active_(false),
100 next_frame_id_(FrameId::first()), 94 next_frame_id_(FrameId::first()),
101 key_frame_encountered_(false), 95 key_frame_encountered_(false),
102 codec_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), 96 codec_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN),
103 key_frame_quantizer_parsable_(false), 97 key_frame_quantizer_parsable_(false),
104 requested_bit_rate_(-1), 98 requested_bit_rate_(-1),
105 has_seen_zero_length_encoded_frame_(false), 99 has_seen_zero_length_encoded_frame_(false) {}
106 max_allowed_input_buffers_(0),
107 allocate_input_buffer_in_progress_(false) {}
108 100
109 base::SingleThreadTaskRunner* task_runner() const { 101 base::SingleThreadTaskRunner* task_runner() const {
110 return task_runner_.get(); 102 return task_runner_.get();
111 } 103 }
112 104
113 void Initialize(const gfx::Size& frame_size, 105 void Initialize(const gfx::Size& frame_size,
114 VideoCodecProfile codec_profile, 106 VideoCodecProfile codec_profile,
115 int start_bit_rate, 107 int start_bit_rate,
116 FrameId first_frame_id) { 108 FrameId first_frame_id) {
117 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 109 DCHECK(task_runner_->RunsTasksOnCurrentThread());
(...skipping 17 matching lines...) Expand all
135 } 127 }
136 128
137 void SetBitRate(int bit_rate) { 129 void SetBitRate(int bit_rate) {
138 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 130 DCHECK(task_runner_->RunsTasksOnCurrentThread());
139 131
140 requested_bit_rate_ = bit_rate; 132 requested_bit_rate_ = bit_rate;
141 video_encode_accelerator_->RequestEncodingParametersChange(bit_rate, 133 video_encode_accelerator_->RequestEncodingParametersChange(bit_rate,
142 max_frame_rate_); 134 max_frame_rate_);
143 } 135 }
144 136
145 // The destruction call back of the copied video frame to free its use of
146 // the input buffer.
147 void ReturnInputBufferToPool(int index) {
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
154 void EncodeVideoFrame( 137 void EncodeVideoFrame(
155 const scoped_refptr<media::VideoFrame>& video_frame, 138 const scoped_refptr<media::VideoFrame>& video_frame,
156 const base::TimeTicks& reference_time, 139 const base::TimeTicks& reference_time,
157 bool key_frame_requested, 140 bool key_frame_requested,
158 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) { 141 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) {
159 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 142 DCHECK(task_runner_->RunsTasksOnCurrentThread());
160 143
161 if (!encoder_active_) 144 if (!encoder_active_)
162 return; 145 return;
163 146
164 in_progress_frame_encodes_.push_back(InProgressFrameEncode( 147 in_progress_frame_encodes_.push_back(InProgressFrameEncode(
165 video_frame, reference_time, frame_encoded_callback, 148 video_frame, reference_time, frame_encoded_callback,
166 requested_bit_rate_)); 149 requested_bit_rate_));
167 150
168 scoped_refptr<media::VideoFrame> frame = video_frame;
169 if (video_frame->coded_size() != frame_coded_size_) {
170 DCHECK_GE(frame_coded_size_.width(), video_frame->visible_rect().width());
171 DCHECK_GE(frame_coded_size_.height(),
172 video_frame->visible_rect().height());
173
174 if (free_input_buffer_index_.empty()) {
175 if (!allocate_input_buffer_in_progress_ &&
176 input_buffers_.size() < max_allowed_input_buffers_) {
177 allocate_input_buffer_in_progress_ = true;
178 create_video_encode_memory_cb_.Run(
179 media::VideoFrame::AllocationSize(media::PIXEL_FORMAT_I420,
180 frame_coded_size_),
181 base::Bind(&VEAClientImpl::OnCreateInputSharedMemory, this));
182 }
183 ExitEncodingWithErrors();
184 return;
185 }
186
187 int index = free_input_buffer_index_.back();
188 base::SharedMemory* input_buffer = input_buffers_[index].get();
189 frame = VideoFrame::WrapExternalSharedMemory(
190 video_frame->format(), frame_coded_size_, video_frame->visible_rect(),
191 video_frame->visible_rect().size(),
192 static_cast<uint8_t*>(input_buffer->memory()),
193 input_buffer->mapped_size(), input_buffer->handle(), 0,
194 video_frame->timestamp());
195 if (!frame || !media::I420CopyWithPadding(*video_frame, frame.get())) {
196 LOG(DFATAL) << "Error: ExternalVideoEncoder: copy failed.";
197 ExitEncodingWithErrors();
198 return;
199 }
200
201 frame->AddDestructionObserver(media::BindToCurrentLoop(base::Bind(
202 &ExternalVideoEncoder::VEAClientImpl::ReturnInputBufferToPool, this,
203 index)));
204 free_input_buffer_index_.pop_back();
205 }
206
207 // BitstreamBufferReady will be called once the encoder is done. 151 // BitstreamBufferReady will be called once the encoder is done.
208 video_encode_accelerator_->Encode(frame, key_frame_requested); 152 video_encode_accelerator_->Encode(video_frame, key_frame_requested);
209 } 153 }
210 154
211 protected: 155 protected:
212 void NotifyError(VideoEncodeAccelerator::Error error) final { 156 void NotifyError(VideoEncodeAccelerator::Error error) final {
213 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 157 DCHECK(task_runner_->RunsTasksOnCurrentThread());
214 158
215 DCHECK(error != VideoEncodeAccelerator::kInvalidArgumentError && 159 DCHECK(error != VideoEncodeAccelerator::kInvalidArgumentError &&
216 error != VideoEncodeAccelerator::kIllegalStateError); 160 error != VideoEncodeAccelerator::kIllegalStateError);
217 161
218 encoder_active_ = false; 162 encoder_active_ = false;
219 163
220 cast_environment_->PostTask( 164 cast_environment_->PostTask(
221 CastEnvironment::MAIN, 165 CastEnvironment::MAIN,
222 FROM_HERE, 166 FROM_HERE,
223 base::Bind(status_change_cb_, STATUS_CODEC_RUNTIME_ERROR)); 167 base::Bind(status_change_cb_, STATUS_CODEC_RUNTIME_ERROR));
224 168
225 // TODO(miu): Force-flush all |in_progress_frame_encodes_| immediately so 169 // TODO(miu): Force-flush all |in_progress_frame_encodes_| immediately so
226 // pending frames do not become stuck, freezing VideoSender. 170 // pending frames do not become stuck, freezing VideoSender.
227 } 171 }
228 172
229 // Called to allocate the input and output buffers. 173 // Called to allocate the input and output buffers.
230 void RequireBitstreamBuffers(unsigned int input_count, 174 void RequireBitstreamBuffers(unsigned int input_count,
231 const gfx::Size& input_coded_size, 175 const gfx::Size& input_coded_size,
232 size_t output_buffer_size) final { 176 size_t output_buffer_size) final {
233 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 177 DCHECK(task_runner_->RunsTasksOnCurrentThread());
234 178
235 frame_coded_size_ = input_coded_size; 179 // TODO(miu): Investigate why we are ignoring |input_count| (4) and instead
236 180 // using |kOutputBufferCount| (3) here.
237 max_allowed_input_buffers_ = input_count + kExtraInputBufferCount;
238
239 for (size_t j = 0; j < kOutputBufferCount; ++j) { 181 for (size_t j = 0; j < kOutputBufferCount; ++j) {
240 create_video_encode_memory_cb_.Run( 182 create_video_encode_memory_cb_.Run(
241 output_buffer_size, 183 output_buffer_size,
242 base::Bind(&VEAClientImpl::OnCreateSharedMemory, this)); 184 base::Bind(&VEAClientImpl::OnCreateSharedMemory, this));
243 } 185 }
244 } 186 }
245 187
246 // Encoder has encoded a frame and it's available in one of the output 188 // Encoder has encoded a frame and it's available in one of the output
247 // buffers. Package the result in a media::cast::EncodedFrame and post it 189 // buffers. Package the result in a media::cast::EncodedFrame and post it
248 // to the Cast MAIN thread via the supplied callback. 190 // to the Cast MAIN thread via the supplied callback.
249 void BitstreamBufferReady(int32_t bitstream_buffer_id, 191 void BitstreamBufferReady(int32_t bitstream_buffer_id,
250 size_t payload_size, 192 size_t payload_size,
251 bool key_frame) final { 193 bool key_frame) final {
252 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 194 DCHECK(task_runner_->RunsTasksOnCurrentThread());
253 if (bitstream_buffer_id < 0 || 195 if (bitstream_buffer_id < 0 ||
254 bitstream_buffer_id >= static_cast<int32_t>(output_buffers_.size())) { 196 bitstream_buffer_id >= static_cast<int32_t>(output_buffers_.size())) {
255 NOTREACHED(); 197 NOTREACHED();
256 VLOG(1) << "BitstreamBufferReady(): invalid bitstream_buffer_id=" 198 VLOG(1) << "BitstreamBufferReady(): invalid bitstream_buffer_id="
257 << bitstream_buffer_id; 199 << bitstream_buffer_id;
258 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); 200 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
259 return; 201 return;
260 } 202 }
261 base::SharedMemory* output_buffer = 203 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id];
262 output_buffers_[bitstream_buffer_id].get();
263 if (payload_size > output_buffer->mapped_size()) { 204 if (payload_size > output_buffer->mapped_size()) {
264 NOTREACHED(); 205 NOTREACHED();
265 VLOG(1) << "BitstreamBufferReady(): invalid payload_size = " 206 VLOG(1) << "BitstreamBufferReady(): invalid payload_size = "
266 << payload_size; 207 << payload_size;
267 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); 208 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
268 return; 209 return;
269 } 210 }
270 if (key_frame) 211 if (key_frame)
271 key_frame_encountered_ = true; 212 key_frame_encountered_ = true;
272 if (!key_frame_encountered_) { 213 if (!key_frame_encountered_) {
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 } 361 }
421 362
422 // Note: This method can be called on any thread. 363 // Note: This method can be called on any thread.
423 void OnCreateSharedMemory(std::unique_ptr<base::SharedMemory> memory) { 364 void OnCreateSharedMemory(std::unique_ptr<base::SharedMemory> memory) {
424 task_runner_->PostTask(FROM_HERE, 365 task_runner_->PostTask(FROM_HERE,
425 base::Bind(&VEAClientImpl::OnReceivedSharedMemory, 366 base::Bind(&VEAClientImpl::OnReceivedSharedMemory,
426 this, 367 this,
427 base::Passed(&memory))); 368 base::Passed(&memory)));
428 } 369 }
429 370
430 void OnCreateInputSharedMemory(std::unique_ptr<base::SharedMemory> memory) {
431 task_runner_->PostTask(
432 FROM_HERE, base::Bind(&VEAClientImpl::OnReceivedInputSharedMemory, this,
433 base::Passed(&memory)));
434 }
435
436 void OnReceivedSharedMemory(std::unique_ptr<base::SharedMemory> memory) { 371 void OnReceivedSharedMemory(std::unique_ptr<base::SharedMemory> memory) {
437 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 372 DCHECK(task_runner_->RunsTasksOnCurrentThread());
438 373
439 output_buffers_.push_back(std::move(memory)); 374 output_buffers_.push_back(std::move(memory));
440 375
441 // Wait until all requested buffers are received. 376 // Wait until all requested buffers are received.
442 if (output_buffers_.size() < kOutputBufferCount) 377 if (output_buffers_.size() < kOutputBufferCount)
443 return; 378 return;
444 379
445 // Immediately provide all output buffers to the VEA. 380 // Immediately provide all output buffers to the VEA.
446 for (size_t i = 0; i < output_buffers_.size(); ++i) { 381 for (size_t i = 0; i < output_buffers_.size(); ++i) {
447 video_encode_accelerator_->UseOutputBitstreamBuffer( 382 video_encode_accelerator_->UseOutputBitstreamBuffer(
448 media::BitstreamBuffer(static_cast<int32_t>(i), 383 media::BitstreamBuffer(static_cast<int32_t>(i),
449 output_buffers_[i]->handle(), 384 output_buffers_[i]->handle(),
450 output_buffers_[i]->mapped_size())); 385 output_buffers_[i]->mapped_size()));
451 } 386 }
452 } 387 }
453 388
454 void OnReceivedInputSharedMemory(std::unique_ptr<base::SharedMemory> memory) {
455 DCHECK(task_runner_->RunsTasksOnCurrentThread());
456
457 if (memory.get()) {
458 input_buffers_.push_back(std::move(memory));
459 free_input_buffer_index_.push_back(input_buffers_.size() - 1);
460 }
461 allocate_input_buffer_in_progress_ = false;
462 }
463
464 // This is called when copy errors occur in encoding process when there is
465 // need to copy the VideoFrames to match the required coded size for encoder.
466 void ExitEncodingWithErrors() {
467 DCHECK(task_runner_->RunsTasksOnCurrentThread());
468
469 std::unique_ptr<SenderEncodedFrame> no_result(nullptr);
470 cast_environment_->PostTask(
471 CastEnvironment::MAIN, FROM_HERE,
472 base::Bind(in_progress_frame_encodes_.back().frame_encoded_callback,
473 base::Passed(&no_result)));
474 in_progress_frame_encodes_.pop_back();
475 }
476
477 // Parse H264 SPS, PPS, and Slice header, and return the averaged frame 389 // Parse H264 SPS, PPS, and Slice header, and return the averaged frame
478 // quantizer in the range of [0, 51], or -1 on parse error. 390 // quantizer in the range of [0, 51], or -1 on parse error.
479 double GetH264FrameQuantizer(const uint8_t* encoded_data, off_t size) { 391 double GetH264FrameQuantizer(const uint8_t* encoded_data, off_t size) {
480 DCHECK(encoded_data); 392 DCHECK(encoded_data);
481 if (!size) 393 if (!size)
482 return -1; 394 return -1;
483 h264_parser_.SetStream(encoded_data, size); 395 h264_parser_.SetStream(encoded_data, size);
484 double total_quantizer = 0; 396 double total_quantizer = 0;
485 int num_slices = 0; 397 int num_slices = 0;
486 398
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
541 std::unique_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; 453 std::unique_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_;
542 bool encoder_active_; 454 bool encoder_active_;
543 FrameId next_frame_id_; 455 FrameId next_frame_id_;
544 bool key_frame_encountered_; 456 bool key_frame_encountered_;
545 std::string stream_header_; 457 std::string stream_header_;
546 VideoCodecProfile codec_profile_; 458 VideoCodecProfile codec_profile_;
547 bool key_frame_quantizer_parsable_; 459 bool key_frame_quantizer_parsable_;
548 H264Parser h264_parser_; 460 H264Parser h264_parser_;
549 461
550 // Shared memory buffers for output with the VideoAccelerator. 462 // Shared memory buffers for output with the VideoAccelerator.
551 std::vector<std::unique_ptr<base::SharedMemory>> output_buffers_; 463 ScopedVector<base::SharedMemory> output_buffers_;
552
553 // Shared memory buffers for input video frames with the VideoAccelerator.
554 // These buffers will be allocated only when copy is needed to match the
555 // required coded size for encoder. They are allocated on-demand, up to
556 // |max_allowed_input_buffers_|.
557 std::vector<std::unique_ptr<base::SharedMemory>> input_buffers_;
558
559 // Available input buffer index. These buffers are used in FILO order.
560 std::vector<int> free_input_buffer_index_;
561 464
562 // FIFO list. 465 // FIFO list.
563 std::list<InProgressFrameEncode> in_progress_frame_encodes_; 466 std::list<InProgressFrameEncode> in_progress_frame_encodes_;
564 467
565 // The requested encode bit rate for the next frame. 468 // The requested encode bit rate for the next frame.
566 int requested_bit_rate_; 469 int requested_bit_rate_;
567 470
568 // Used to compute utilization metrics for each frame. 471 // Used to compute utilization metrics for each frame.
569 QuantizerEstimator quantizer_estimator_; 472 QuantizerEstimator quantizer_estimator_;
570 473
571 // Set to true once a frame with zero-length encoded data has been 474 // Set to true once a frame with zero-length encoded data has been
572 // encountered. 475 // encountered.
573 // TODO(miu): Remove after discovering cause. http://crbug.com/519022 476 // TODO(miu): Remove after discovering cause. http://crbug.com/519022
574 bool has_seen_zero_length_encoded_frame_; 477 bool has_seen_zero_length_encoded_frame_;
575 478
576 // The coded size of the video frame required by Encoder. This size is
577 // obtained from VEA through |RequireBitstreamBuffers()|.
578 gfx::Size frame_coded_size_;
579
580 // The maximum number of input buffers. These buffers are used to copy
581 // VideoFrames in order to match the required coded size for encoder.
582 size_t max_allowed_input_buffers_;
583
584 // Set to true when the allocation of an input buffer is in progress, and
585 // reset to false after the allocated buffer is received.
586 bool allocate_input_buffer_in_progress_;
587
588 DISALLOW_COPY_AND_ASSIGN(VEAClientImpl); 479 DISALLOW_COPY_AND_ASSIGN(VEAClientImpl);
589 }; 480 };
590 481
591 // static 482 // static
592 bool ExternalVideoEncoder::IsSupported(const VideoSenderConfig& video_config) { 483 bool ExternalVideoEncoder::IsSupported(const VideoSenderConfig& video_config) {
593 if (video_config.codec != CODEC_VIDEO_VP8 && 484 if (video_config.codec != CODEC_VIDEO_VP8 &&
594 video_config.codec != CODEC_VIDEO_H264) 485 video_config.codec != CODEC_VIDEO_H264)
595 return false; 486 return false;
596 487
597 // TODO(miu): "Layering hooks" are needed to be able to query outside of 488 // TODO(miu): "Layering hooks" are needed to be able to query outside of
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
893 const double kEntropyAtMaxQuantizer = 7.5; 784 const double kEntropyAtMaxQuantizer = 7.5;
894 const double slope = 785 const double slope =
895 (MAX_VP8_QUANTIZER - MIN_VP8_QUANTIZER) / kEntropyAtMaxQuantizer; 786 (MAX_VP8_QUANTIZER - MIN_VP8_QUANTIZER) / kEntropyAtMaxQuantizer;
896 const double quantizer = std::min<double>( 787 const double quantizer = std::min<double>(
897 MAX_VP8_QUANTIZER, MIN_VP8_QUANTIZER + slope * shannon_entropy); 788 MAX_VP8_QUANTIZER, MIN_VP8_QUANTIZER + slope * shannon_entropy);
898 return quantizer; 789 return quantizer;
899 } 790 }
900 791
901 } // namespace cast 792 } // namespace cast
902 } // namespace media 793 } // namespace media
OLDNEW
« no previous file with comments | « media/base/video_util_unittest.cc ('k') | media/cast/sender/size_adaptable_video_encoder_base.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698