OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |