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

Side by Side Diff: media/gpu/android_video_encode_accelerator.cc

Issue 2358683002: Android: enable/disable WebRTC HW H264 with a flag. (Closed)
Patch Set: rebase to Oct17 Created 4 years, 2 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 | « media/gpu/android_video_encode_accelerator.h ('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 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/gpu/android_video_encode_accelerator.h" 5 #include "media/gpu/android_video_encode_accelerator.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <set> 8 #include <set>
9 #include <tuple> 9 #include <tuple>
10 10
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 } 101 }
102 102
103 VideoEncodeAccelerator::SupportedProfiles 103 VideoEncodeAccelerator::SupportedProfiles
104 AndroidVideoEncodeAccelerator::GetSupportedProfiles() { 104 AndroidVideoEncodeAccelerator::GetSupportedProfiles() {
105 SupportedProfiles profiles; 105 SupportedProfiles profiles;
106 106
107 const struct { 107 const struct {
108 const VideoCodec codec; 108 const VideoCodec codec;
109 const VideoCodecProfile profile; 109 const VideoCodecProfile profile;
110 } kSupportedCodecs[] = {{kCodecVP8, VP8PROFILE_ANY}, 110 } kSupportedCodecs[] = {{kCodecVP8, VP8PROFILE_ANY},
111 {kCodecH264, H264PROFILE_BASELINE}, 111 {kCodecH264, H264PROFILE_BASELINE}};
112 {kCodecH264, H264PROFILE_MAIN}};
113 112
114 for (const auto& supported_codec : kSupportedCodecs) { 113 for (const auto& supported_codec : kSupportedCodecs) {
115 if (supported_codec.codec == kCodecVP8 && 114 if (supported_codec.codec == kCodecVP8 &&
116 !MediaCodecUtil::IsVp8EncoderAvailable()) { 115 !MediaCodecUtil::IsVp8EncoderAvailable()) {
117 continue; 116 continue;
118 } 117 }
119 118
119 if (supported_codec.codec == kCodecH264 &&
120 !MediaCodecUtil::IsH264EncoderAvailable()) {
121 continue;
122 }
123
120 if (VideoCodecBridge::IsKnownUnaccelerated(supported_codec.codec, 124 if (VideoCodecBridge::IsKnownUnaccelerated(supported_codec.codec,
121 MEDIA_CODEC_ENCODER)) { 125 MEDIA_CODEC_ENCODER)) {
122 continue; 126 continue;
123 } 127 }
124 128
125 SupportedProfile profile; 129 SupportedProfile profile;
126 profile.profile = supported_codec.profile; 130 profile.profile = supported_codec.profile;
127 // It would be nice if MediaCodec exposes the maximum capabilities of 131 // It would be nice if MediaCodec exposes the maximum capabilities of
128 // the encoder. Hard-code some reasonable defaults as workaround. 132 // the encoder. Hard-code some reasonable defaults as workaround.
129 profile.max_resolution.SetSize(kMaxEncodeFrameWidth, kMaxEncodeFrameHeight); 133 profile.max_resolution.SetSize(kMaxEncodeFrameWidth, kMaxEncodeFrameHeight);
(...skipping 24 matching lines...) Expand all
154 DLOG(ERROR) << "Unexpected combo: " << format << ", " << output_profile; 158 DLOG(ERROR) << "Unexpected combo: " << format << ", " << output_profile;
155 return false; 159 return false;
156 } 160 }
157 161
158 std::string mime_type; 162 std::string mime_type;
159 VideoCodec codec; 163 VideoCodec codec;
160 // The client should be prepared to feed at least this many frames into the 164 // The client should be prepared to feed at least this many frames into the
161 // encoder before being returned any output frames, since the encoder may 165 // encoder before being returned any output frames, since the encoder may
162 // need to hold onto some subset of inputs as reference pictures. 166 // need to hold onto some subset of inputs as reference pictures.
163 uint32_t frame_input_count; 167 uint32_t frame_input_count;
168 uint32_t i_frame_interval;
164 if (output_profile == VP8PROFILE_ANY) { 169 if (output_profile == VP8PROFILE_ANY) {
165 codec = kCodecVP8; 170 codec = kCodecVP8;
166 mime_type = "video/x-vnd.on2.vp8"; 171 mime_type = "video/x-vnd.on2.vp8";
167 frame_input_count = 1; 172 frame_input_count = 1;
173 i_frame_interval = IFRAME_INTERVAL_VPX;
168 } else if (output_profile == H264PROFILE_BASELINE || 174 } else if (output_profile == H264PROFILE_BASELINE ||
169 output_profile == H264PROFILE_MAIN) { 175 output_profile == H264PROFILE_MAIN) {
170 codec = kCodecH264; 176 codec = kCodecH264;
171 mime_type = "video/avc"; 177 mime_type = "video/avc";
172 frame_input_count = 30; 178 frame_input_count = 30;
179 i_frame_interval = IFRAME_INTERVAL_H264;
173 } else { 180 } else {
174 return false; 181 return false;
175 } 182 }
176 183
177 frame_size_ = input_visible_size; 184 frame_size_ = input_visible_size;
178 last_set_bitrate_ = initial_bitrate; 185 last_set_bitrate_ = initial_bitrate;
179 186
180 // Only consider using MediaCodec if it's likely backed by hardware. 187 // Only consider using MediaCodec if it's likely backed by hardware.
181 if (VideoCodecBridge::IsKnownUnaccelerated(codec, MEDIA_CODEC_ENCODER)) { 188 if (VideoCodecBridge::IsKnownUnaccelerated(codec, MEDIA_CODEC_ENCODER)) {
182 DLOG(ERROR) << "No HW support"; 189 DLOG(ERROR) << "No HW support";
183 return false; 190 return false;
184 } 191 }
185 192
186 PixelFormat pixel_format = COLOR_FORMAT_YUV420_SEMIPLANAR; 193 PixelFormat pixel_format = COLOR_FORMAT_YUV420_SEMIPLANAR;
187 if (!GetSupportedColorFormatForMime(mime_type, &pixel_format)) { 194 if (!GetSupportedColorFormatForMime(mime_type, &pixel_format)) {
188 DLOG(ERROR) << "No color format support."; 195 DLOG(ERROR) << "No color format support.";
189 return false; 196 return false;
190 } 197 }
191 media_codec_.reset(VideoCodecBridge::CreateEncoder( 198 media_codec_.reset(VideoCodecBridge::CreateEncoder(
192 codec, input_visible_size, initial_bitrate, INITIAL_FRAMERATE, 199 codec, input_visible_size, initial_bitrate, INITIAL_FRAMERATE,
193 IFRAME_INTERVAL, pixel_format)); 200 i_frame_interval, pixel_format));
194 201
195 if (!media_codec_) { 202 if (!media_codec_) {
196 DLOG(ERROR) << "Failed to create/start the codec: " 203 DLOG(ERROR) << "Failed to create/start the codec: "
197 << input_visible_size.ToString(); 204 << input_visible_size.ToString();
198 return false; 205 return false;
199 } 206 }
200 207
201 // Conservative upper bound for output buffer size: decoded size + 2KB. 208 // Conservative upper bound for output buffer size: decoded size + 2KB.
202 const size_t output_buffer_capacity = 209 const size_t output_buffer_capacity =
203 VideoFrame::AllocationSize(format, input_visible_size) + 2048; 210 VideoFrame::AllocationSize(format, input_visible_size) + 2048;
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 // Why NV12? Because COLOR_FORMAT_YUV420_SEMIPLANAR. See comment at other 347 // Why NV12? Because COLOR_FORMAT_YUV420_SEMIPLANAR. See comment at other
341 // mention of that constant. 348 // mention of that constant.
342 bool converted = !libyuv::I420ToNV12( 349 bool converted = !libyuv::I420ToNV12(
343 frame->data(VideoFrame::kYPlane), frame->stride(VideoFrame::kYPlane), 350 frame->data(VideoFrame::kYPlane), frame->stride(VideoFrame::kYPlane),
344 frame->data(VideoFrame::kUPlane), frame->stride(VideoFrame::kUPlane), 351 frame->data(VideoFrame::kUPlane), frame->stride(VideoFrame::kUPlane),
345 frame->data(VideoFrame::kVPlane), frame->stride(VideoFrame::kVPlane), 352 frame->data(VideoFrame::kVPlane), frame->stride(VideoFrame::kVPlane),
346 dst_y, dst_stride_y, dst_uv, dst_stride_uv, frame->coded_size().width(), 353 dst_y, dst_stride_y, dst_uv, dst_stride_uv, frame->coded_size().width(),
347 frame->coded_size().height()); 354 frame->coded_size().height());
348 RETURN_ON_FAILURE(converted, "Failed to I420ToNV12!", kPlatformFailureError); 355 RETURN_ON_FAILURE(converted, "Failed to I420ToNV12!", kPlatformFailureError);
349 356
350 fake_input_timestamp_ += base::TimeDelta::FromMicroseconds(1); 357 input_timestamp_ += base::TimeDelta::FromMicroseconds(
358 base::Time::kMicrosecondsPerSecond / INITIAL_FRAMERATE);
351 status = media_codec_->QueueInputBuffer(input_buf_index, nullptr, queued_size, 359 status = media_codec_->QueueInputBuffer(input_buf_index, nullptr, queued_size,
352 fake_input_timestamp_); 360 input_timestamp_);
353 UMA_HISTOGRAM_TIMES("Media.AVDA.InputQueueTime", 361 UMA_HISTOGRAM_TIMES("Media.AVDA.InputQueueTime",
354 base::Time::Now() - std::get<2>(input)); 362 base::Time::Now() - std::get<2>(input));
355 RETURN_ON_FAILURE(status == MEDIA_CODEC_OK, 363 RETURN_ON_FAILURE(status == MEDIA_CODEC_OK,
356 "Failed to QueueInputBuffer: " << status, 364 "Failed to QueueInputBuffer: " << status,
357 kPlatformFailureError); 365 kPlatformFailureError);
358 ++num_buffers_at_codec_; 366 ++num_buffers_at_codec_;
359 pending_frames_.pop(); 367 pending_frames_.pop();
360 } 368 }
361 369
362 void AndroidVideoEncodeAccelerator::DequeueOutput() { 370 void AndroidVideoEncodeAccelerator::DequeueOutput() {
363 if (!client_ptr_factory_->GetWeakPtr() || 371 if (!client_ptr_factory_->GetWeakPtr() ||
364 available_bitstream_buffers_.empty() || num_buffers_at_codec_ == 0) { 372 available_bitstream_buffers_.empty() || num_buffers_at_codec_ == 0) {
365 return; 373 return;
366 } 374 }
367 375
368 int32_t buf_index = 0; 376 int32_t buf_index = 0;
369 size_t offset = 0; 377 size_t offset = 0;
370 size_t size = 0; 378 size_t size = 0;
371 bool key_frame = false; 379 bool key_frame = false;
372 do {
373 MediaCodecStatus status =
374 media_codec_->DequeueOutputBuffer(NoWaitTimeOut(), &buf_index, &offset,
375 &size, nullptr, nullptr, &key_frame);
376 switch (status) {
377 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
378 return;
379 380
380 case MEDIA_CODEC_ERROR: 381 MediaCodecStatus status =
381 RETURN_ON_FAILURE(false, "Codec error", kPlatformFailureError); 382 media_codec_->DequeueOutputBuffer(NoWaitTimeOut(), &buf_index, &offset,
382 // Unreachable because of previous statement, but included for clarity. 383 &size, nullptr, nullptr, &key_frame);
383 return; 384 switch (status) {
385 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
386 return;
384 387
385 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: 388 case MEDIA_CODEC_ERROR:
386 break; 389 RETURN_ON_FAILURE(false, "Codec error", kPlatformFailureError);
390 // Unreachable because of previous statement, but included for clarity.
391 return;
387 392
388 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: 393 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
389 break; 394 return;
390 395
391 case MEDIA_CODEC_OK: 396 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED:
392 DCHECK_GE(buf_index, 0); 397 return;
393 break;
394 398
395 default: 399 case MEDIA_CODEC_OK:
396 NOTREACHED(); 400 DCHECK_GE(buf_index, 0);
397 break; 401 break;
398 } 402
399 } while (buf_index < 0); 403 default:
404 NOTREACHED();
405 break;
406 }
400 407
401 BitstreamBuffer bitstream_buffer = available_bitstream_buffers_.back(); 408 BitstreamBuffer bitstream_buffer = available_bitstream_buffers_.back();
402 available_bitstream_buffers_.pop_back(); 409 available_bitstream_buffers_.pop_back();
403 std::unique_ptr<SharedMemoryRegion> shm( 410 std::unique_ptr<SharedMemoryRegion> shm(
404 new SharedMemoryRegion(bitstream_buffer, false)); 411 new SharedMemoryRegion(bitstream_buffer, false));
405 RETURN_ON_FAILURE(shm->Map(), "Failed to map SHM", kPlatformFailureError); 412 RETURN_ON_FAILURE(shm->Map(), "Failed to map SHM", kPlatformFailureError);
406 RETURN_ON_FAILURE(size <= shm->size(), 413 RETURN_ON_FAILURE(size <= shm->size(),
407 "Encoded buffer too large: " << size << ">" << shm->size(), 414 "Encoded buffer too large: " << size << ">" << shm->size(),
408 kPlatformFailureError); 415 kPlatformFailureError);
409 416
410 MediaCodecStatus status = media_codec_->CopyFromOutputBuffer( 417 status = media_codec_->CopyFromOutputBuffer(buf_index, offset, shm->memory(),
411 buf_index, offset, shm->memory(), size); 418 size);
412 RETURN_ON_FAILURE(status == MEDIA_CODEC_OK, "CopyFromOutputBuffer failed", 419 RETURN_ON_FAILURE(status == MEDIA_CODEC_OK, "CopyFromOutputBuffer failed",
413 kPlatformFailureError); 420 kPlatformFailureError);
414 media_codec_->ReleaseOutputBuffer(buf_index, false); 421 media_codec_->ReleaseOutputBuffer(buf_index, false);
415 --num_buffers_at_codec_; 422 --num_buffers_at_codec_;
416 423
417 base::ThreadTaskRunnerHandle::Get()->PostTask( 424 base::ThreadTaskRunnerHandle::Get()->PostTask(
418 FROM_HERE, 425 FROM_HERE,
419 base::Bind(&VideoEncodeAccelerator::Client::BitstreamBufferReady, 426 base::Bind(&VideoEncodeAccelerator::Client::BitstreamBufferReady,
420 client_ptr_factory_->GetWeakPtr(), bitstream_buffer.id(), size, 427 client_ptr_factory_->GetWeakPtr(), bitstream_buffer.id(), size,
421 key_frame, base::Time::Now() - base::Time())); 428 key_frame, base::Time::Now() - base::Time()));
422 } 429 }
423 430
424 } // namespace media 431 } // namespace media
OLDNEW
« no previous file with comments | « media/gpu/android_video_encode_accelerator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698