| 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 "content/common/gpu/media/android_video_encode_accelerator.h" | 5 #include "media/gpu/android_video_encode_accelerator.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/message_loop/message_loop.h" | 11 #include "base/message_loop/message_loop.h" |
| 12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "content/common/gpu/media/shared_memory_region.h" | |
| 14 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" | 13 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" |
| 15 #include "gpu/ipc/service/gpu_channel.h" | 14 #include "gpu/ipc/service/gpu_channel.h" |
| 16 #include "media/base/android/media_codec_util.h" | 15 #include "media/base/android/media_codec_util.h" |
| 17 #include "media/base/bitstream_buffer.h" | 16 #include "media/base/bitstream_buffer.h" |
| 18 #include "media/base/limits.h" | 17 #include "media/base/limits.h" |
| 18 #include "media/gpu/shared_memory_region.h" |
| 19 #include "media/video/picture.h" | 19 #include "media/video/picture.h" |
| 20 #include "third_party/libyuv/include/libyuv/convert_from.h" | 20 #include "third_party/libyuv/include/libyuv/convert_from.h" |
| 21 #include "ui/gl/android/scoped_java_surface.h" | 21 #include "ui/gl/android/scoped_java_surface.h" |
| 22 #include "ui/gl/gl_bindings.h" | 22 #include "ui/gl/gl_bindings.h" |
| 23 | 23 |
| 24 using media::VideoCodecBridge; | 24 using media::VideoCodecBridge; |
| 25 using media::VideoFrame; | 25 using media::VideoFrame; |
| 26 | 26 |
| 27 namespace content { | 27 namespace media { |
| 28 | 28 |
| 29 // Limit default max video codec size for Android to avoid | 29 // Limit default max video codec size for Android to avoid |
| 30 // HW codec initialization failure for resolution higher than 720p. | 30 // HW codec initialization failure for resolution higher than 720p. |
| 31 // Default values are from Libjingle "jsepsessiondescription.cc". | 31 // Default values are from Libjingle "jsepsessiondescription.cc". |
| 32 const int kMaxEncodeFrameWidth = 1280; | 32 const int kMaxEncodeFrameWidth = 1280; |
| 33 const int kMaxEncodeFrameHeight = 720; | 33 const int kMaxEncodeFrameHeight = 720; |
| 34 const int kMaxFramerateNumerator = 30; | 34 const int kMaxFramerateNumerator = 30; |
| 35 const int kMaxFramerateDenominator = 1; | 35 const int kMaxFramerateDenominator = 1; |
| 36 | 36 |
| 37 enum PixelFormat { | 37 enum PixelFormat { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 *pixel_format = COLOR_FORMAT_YUV420_SEMIPLANAR; | 86 *pixel_format = COLOR_FORMAT_YUV420_SEMIPLANAR; |
| 87 else if (formats.count(COLOR_FORMAT_YUV420_PLANAR) > 0) | 87 else if (formats.count(COLOR_FORMAT_YUV420_PLANAR) > 0) |
| 88 *pixel_format = COLOR_FORMAT_YUV420_PLANAR; | 88 *pixel_format = COLOR_FORMAT_YUV420_PLANAR; |
| 89 else | 89 else |
| 90 return false; | 90 return false; |
| 91 | 91 |
| 92 return true; | 92 return true; |
| 93 } | 93 } |
| 94 | 94 |
| 95 AndroidVideoEncodeAccelerator::AndroidVideoEncodeAccelerator() | 95 AndroidVideoEncodeAccelerator::AndroidVideoEncodeAccelerator() |
| 96 : num_buffers_at_codec_(0), | 96 : num_buffers_at_codec_(0), last_set_bitrate_(0) {} |
| 97 last_set_bitrate_(0) {} | |
| 98 | 97 |
| 99 AndroidVideoEncodeAccelerator::~AndroidVideoEncodeAccelerator() { | 98 AndroidVideoEncodeAccelerator::~AndroidVideoEncodeAccelerator() { |
| 100 DCHECK(thread_checker_.CalledOnValidThread()); | 99 DCHECK(thread_checker_.CalledOnValidThread()); |
| 101 } | 100 } |
| 102 | 101 |
| 103 media::VideoEncodeAccelerator::SupportedProfiles | 102 media::VideoEncodeAccelerator::SupportedProfiles |
| 104 AndroidVideoEncodeAccelerator::GetSupportedProfiles() { | 103 AndroidVideoEncodeAccelerator::GetSupportedProfiles() { |
| 105 SupportedProfiles profiles; | 104 SupportedProfiles profiles; |
| 106 | 105 |
| 107 const struct { | 106 const struct { |
| 108 const media::VideoCodec codec; | 107 const media::VideoCodec codec; |
| 109 const media::VideoCodecProfile profile; | 108 const media::VideoCodecProfile profile; |
| 110 } kSupportedCodecs[] = { | 109 } kSupportedCodecs[] = {{media::kCodecVP8, media::VP8PROFILE_ANY}, |
| 111 { media::kCodecVP8, media::VP8PROFILE_ANY }, | 110 {media::kCodecH264, media::H264PROFILE_BASELINE}, |
| 112 { media::kCodecH264, media::H264PROFILE_BASELINE }, | 111 {media::kCodecH264, media::H264PROFILE_MAIN}}; |
| 113 { media::kCodecH264, media::H264PROFILE_MAIN } | |
| 114 }; | |
| 115 | 112 |
| 116 for (const auto& supported_codec : kSupportedCodecs) { | 113 for (const auto& supported_codec : kSupportedCodecs) { |
| 117 if (supported_codec.codec == media::kCodecVP8 && | 114 if (supported_codec.codec == media::kCodecVP8 && |
| 118 !media::MediaCodecUtil::IsVp8EncoderAvailable()) { | 115 !media::MediaCodecUtil::IsVp8EncoderAvailable()) { |
| 119 continue; | 116 continue; |
| 120 } | 117 } |
| 121 | 118 |
| 122 if (VideoCodecBridge::IsKnownUnaccelerated(supported_codec.codec, | 119 if (VideoCodecBridge::IsKnownUnaccelerated(supported_codec.codec, |
| 123 media::MEDIA_CODEC_ENCODER)) { | 120 media::MEDIA_CODEC_ENCODER)) { |
| 124 continue; | 121 continue; |
| 125 } | 122 } |
| 126 | 123 |
| 127 SupportedProfile profile; | 124 SupportedProfile profile; |
| 128 profile.profile = supported_codec.profile; | 125 profile.profile = supported_codec.profile; |
| 129 // It would be nice if MediaCodec exposes the maximum capabilities of | 126 // It would be nice if MediaCodec exposes the maximum capabilities of |
| 130 // the encoder. Hard-code some reasonable defaults as workaround. | 127 // the encoder. Hard-code some reasonable defaults as workaround. |
| 131 profile.max_resolution.SetSize(kMaxEncodeFrameWidth, | 128 profile.max_resolution.SetSize(kMaxEncodeFrameWidth, kMaxEncodeFrameHeight); |
| 132 kMaxEncodeFrameHeight); | |
| 133 profile.max_framerate_numerator = kMaxFramerateNumerator; | 129 profile.max_framerate_numerator = kMaxFramerateNumerator; |
| 134 profile.max_framerate_denominator = kMaxFramerateDenominator; | 130 profile.max_framerate_denominator = kMaxFramerateDenominator; |
| 135 profiles.push_back(profile); | 131 profiles.push_back(profile); |
| 136 } | 132 } |
| 137 return profiles; | 133 return profiles; |
| 138 } | 134 } |
| 139 | 135 |
| 140 bool AndroidVideoEncodeAccelerator::Initialize( | 136 bool AndroidVideoEncodeAccelerator::Initialize( |
| 141 media::VideoPixelFormat format, | 137 media::VideoPixelFormat format, |
| 142 const gfx::Size& input_visible_size, | 138 const gfx::Size& input_visible_size, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 codec, media::MEDIA_CODEC_ENCODER)) { | 181 codec, media::MEDIA_CODEC_ENCODER)) { |
| 186 DLOG(ERROR) << "No HW support"; | 182 DLOG(ERROR) << "No HW support"; |
| 187 return false; | 183 return false; |
| 188 } | 184 } |
| 189 | 185 |
| 190 PixelFormat pixel_format = COLOR_FORMAT_YUV420_SEMIPLANAR; | 186 PixelFormat pixel_format = COLOR_FORMAT_YUV420_SEMIPLANAR; |
| 191 if (!GetSupportedColorFormatForMime(mime_type, &pixel_format)) { | 187 if (!GetSupportedColorFormatForMime(mime_type, &pixel_format)) { |
| 192 DLOG(ERROR) << "No color format support."; | 188 DLOG(ERROR) << "No color format support."; |
| 193 return false; | 189 return false; |
| 194 } | 190 } |
| 195 media_codec_.reset(media::VideoCodecBridge::CreateEncoder(codec, | 191 media_codec_.reset(media::VideoCodecBridge::CreateEncoder( |
| 196 input_visible_size, | 192 codec, input_visible_size, initial_bitrate, INITIAL_FRAMERATE, |
| 197 initial_bitrate, | 193 IFRAME_INTERVAL, pixel_format)); |
| 198 INITIAL_FRAMERATE, | |
| 199 IFRAME_INTERVAL, | |
| 200 pixel_format)); | |
| 201 | 194 |
| 202 if (!media_codec_) { | 195 if (!media_codec_) { |
| 203 DLOG(ERROR) << "Failed to create/start the codec: " | 196 DLOG(ERROR) << "Failed to create/start the codec: " |
| 204 << input_visible_size.ToString(); | 197 << input_visible_size.ToString(); |
| 205 return false; | 198 return false; |
| 206 } | 199 } |
| 207 | 200 |
| 208 // Conservative upper bound for output buffer size: decoded size + 2KB. | 201 // Conservative upper bound for output buffer size: decoded size + 2KB. |
| 209 const size_t output_buffer_capacity = | 202 const size_t output_buffer_capacity = |
| 210 VideoFrame::AllocationSize(format, input_visible_size) + 2048; | 203 VideoFrame::AllocationSize(format, input_visible_size) + 2048; |
| 211 base::MessageLoop::current()->PostTask( | 204 base::MessageLoop::current()->PostTask( |
| 212 FROM_HERE, | 205 FROM_HERE, |
| 213 base::Bind(&VideoEncodeAccelerator::Client::RequireBitstreamBuffers, | 206 base::Bind(&VideoEncodeAccelerator::Client::RequireBitstreamBuffers, |
| 214 client_ptr_factory_->GetWeakPtr(), | 207 client_ptr_factory_->GetWeakPtr(), frame_input_count, |
| 215 frame_input_count, | 208 input_visible_size, output_buffer_capacity)); |
| 216 input_visible_size, | |
| 217 output_buffer_capacity)); | |
| 218 return true; | 209 return true; |
| 219 } | 210 } |
| 220 | 211 |
| 221 void AndroidVideoEncodeAccelerator::MaybeStartIOTimer() { | 212 void AndroidVideoEncodeAccelerator::MaybeStartIOTimer() { |
| 222 if (!io_timer_.IsRunning() && | 213 if (!io_timer_.IsRunning() && |
| 223 (num_buffers_at_codec_ > 0 || !pending_frames_.empty())) { | 214 (num_buffers_at_codec_ > 0 || !pending_frames_.empty())) { |
| 224 io_timer_.Start(FROM_HERE, | 215 io_timer_.Start(FROM_HERE, EncodePollDelay(), this, |
| 225 EncodePollDelay(), | |
| 226 this, | |
| 227 &AndroidVideoEncodeAccelerator::DoIOTask); | 216 &AndroidVideoEncodeAccelerator::DoIOTask); |
| 228 } | 217 } |
| 229 } | 218 } |
| 230 | 219 |
| 231 void AndroidVideoEncodeAccelerator::MaybeStopIOTimer() { | 220 void AndroidVideoEncodeAccelerator::MaybeStopIOTimer() { |
| 232 if (io_timer_.IsRunning() && | 221 if (io_timer_.IsRunning() && |
| 233 (num_buffers_at_codec_ == 0 && pending_frames_.empty())) { | 222 (num_buffers_at_codec_ == 0 && pending_frames_.empty())) { |
| 234 io_timer_.Stop(); | 223 io_timer_.Stop(); |
| 235 } | 224 } |
| 236 } | 225 } |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 void AndroidVideoEncodeAccelerator::QueueInput() { | 296 void AndroidVideoEncodeAccelerator::QueueInput() { |
| 308 if (!client_ptr_factory_->GetWeakPtr() || pending_frames_.empty()) | 297 if (!client_ptr_factory_->GetWeakPtr() || pending_frames_.empty()) |
| 309 return; | 298 return; |
| 310 | 299 |
| 311 int input_buf_index = 0; | 300 int input_buf_index = 0; |
| 312 media::MediaCodecStatus status = | 301 media::MediaCodecStatus status = |
| 313 media_codec_->DequeueInputBuffer(NoWaitTimeOut(), &input_buf_index); | 302 media_codec_->DequeueInputBuffer(NoWaitTimeOut(), &input_buf_index); |
| 314 if (status != media::MEDIA_CODEC_OK) { | 303 if (status != media::MEDIA_CODEC_OK) { |
| 315 DCHECK(status == media::MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER || | 304 DCHECK(status == media::MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER || |
| 316 status == media::MEDIA_CODEC_ERROR); | 305 status == media::MEDIA_CODEC_ERROR); |
| 317 RETURN_ON_FAILURE(status != media::MEDIA_CODEC_ERROR, | 306 RETURN_ON_FAILURE(status != media::MEDIA_CODEC_ERROR, "MediaCodec error", |
| 318 "MediaCodec error", | |
| 319 kPlatformFailureError); | 307 kPlatformFailureError); |
| 320 return; | 308 return; |
| 321 } | 309 } |
| 322 | 310 |
| 323 const PendingFrames::value_type& input = pending_frames_.front(); | 311 const PendingFrames::value_type& input = pending_frames_.front(); |
| 324 bool is_key_frame = base::get<1>(input); | 312 bool is_key_frame = base::get<1>(input); |
| 325 if (is_key_frame) { | 313 if (is_key_frame) { |
| 326 // Ideally MediaCodec would honor BUFFER_FLAG_SYNC_FRAME so we could | 314 // Ideally MediaCodec would honor BUFFER_FLAG_SYNC_FRAME so we could |
| 327 // indicate this in the QueueInputBuffer() call below and guarantee _this_ | 315 // indicate this in the QueueInputBuffer() call below and guarantee _this_ |
| 328 // frame be encoded as a key frame, but sadly that flag is ignored. | 316 // frame be encoded as a key frame, but sadly that flag is ignored. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 344 kPlatformFailureError); | 332 kPlatformFailureError); |
| 345 | 333 |
| 346 uint8_t* dst_y = buffer; | 334 uint8_t* dst_y = buffer; |
| 347 int dst_stride_y = frame->stride(VideoFrame::kYPlane); | 335 int dst_stride_y = frame->stride(VideoFrame::kYPlane); |
| 348 uint8_t* dst_uv = | 336 uint8_t* dst_uv = |
| 349 buffer + | 337 buffer + |
| 350 frame->stride(VideoFrame::kYPlane) * frame->rows(VideoFrame::kYPlane); | 338 frame->stride(VideoFrame::kYPlane) * frame->rows(VideoFrame::kYPlane); |
| 351 int dst_stride_uv = frame->stride(VideoFrame::kUPlane) * 2; | 339 int dst_stride_uv = frame->stride(VideoFrame::kUPlane) * 2; |
| 352 // Why NV12? Because COLOR_FORMAT_YUV420_SEMIPLANAR. See comment at other | 340 // Why NV12? Because COLOR_FORMAT_YUV420_SEMIPLANAR. See comment at other |
| 353 // mention of that constant. | 341 // mention of that constant. |
| 354 bool converted = !libyuv::I420ToNV12(frame->data(VideoFrame::kYPlane), | 342 bool converted = !libyuv::I420ToNV12( |
| 355 frame->stride(VideoFrame::kYPlane), | 343 frame->data(VideoFrame::kYPlane), frame->stride(VideoFrame::kYPlane), |
| 356 frame->data(VideoFrame::kUPlane), | 344 frame->data(VideoFrame::kUPlane), frame->stride(VideoFrame::kUPlane), |
| 357 frame->stride(VideoFrame::kUPlane), | 345 frame->data(VideoFrame::kVPlane), frame->stride(VideoFrame::kVPlane), |
| 358 frame->data(VideoFrame::kVPlane), | 346 dst_y, dst_stride_y, dst_uv, dst_stride_uv, frame->coded_size().width(), |
| 359 frame->stride(VideoFrame::kVPlane), | 347 frame->coded_size().height()); |
| 360 dst_y, | |
| 361 dst_stride_y, | |
| 362 dst_uv, | |
| 363 dst_stride_uv, | |
| 364 frame->coded_size().width(), | |
| 365 frame->coded_size().height()); | |
| 366 RETURN_ON_FAILURE(converted, "Failed to I420ToNV12!", kPlatformFailureError); | 348 RETURN_ON_FAILURE(converted, "Failed to I420ToNV12!", kPlatformFailureError); |
| 367 | 349 |
| 368 fake_input_timestamp_ += base::TimeDelta::FromMicroseconds(1); | 350 fake_input_timestamp_ += base::TimeDelta::FromMicroseconds(1); |
| 369 status = media_codec_->QueueInputBuffer( | 351 status = media_codec_->QueueInputBuffer(input_buf_index, NULL, queued_size, |
| 370 input_buf_index, NULL, queued_size, fake_input_timestamp_); | 352 fake_input_timestamp_); |
| 371 UMA_HISTOGRAM_TIMES("Media.AVEA.InputQueueTime", | 353 UMA_HISTOGRAM_TIMES("Media.AVDA.InputQueueTime", |
| 372 base::Time::Now() - base::get<2>(input)); | 354 base::Time::Now() - base::get<2>(input)); |
| 373 RETURN_ON_FAILURE(status == media::MEDIA_CODEC_OK, | 355 RETURN_ON_FAILURE(status == media::MEDIA_CODEC_OK, |
| 374 "Failed to QueueInputBuffer: " << status, | 356 "Failed to QueueInputBuffer: " << status, |
| 375 kPlatformFailureError); | 357 kPlatformFailureError); |
| 376 ++num_buffers_at_codec_; | 358 ++num_buffers_at_codec_; |
| 377 pending_frames_.pop(); | 359 pending_frames_.pop(); |
| 378 } | 360 } |
| 379 | 361 |
| 380 void AndroidVideoEncodeAccelerator::DequeueOutput() { | 362 void AndroidVideoEncodeAccelerator::DequeueOutput() { |
| 381 if (!client_ptr_factory_->GetWeakPtr() || | 363 if (!client_ptr_factory_->GetWeakPtr() || |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 "Encoded buffer too large: " << size << ">" << shm->size(), | 408 "Encoded buffer too large: " << size << ">" << shm->size(), |
| 427 kPlatformFailureError); | 409 kPlatformFailureError); |
| 428 | 410 |
| 429 media::MediaCodecStatus status = media_codec_->CopyFromOutputBuffer( | 411 media::MediaCodecStatus status = media_codec_->CopyFromOutputBuffer( |
| 430 buf_index, offset, shm->memory(), size); | 412 buf_index, offset, shm->memory(), size); |
| 431 RETURN_ON_FAILURE(status == media::MEDIA_CODEC_OK, | 413 RETURN_ON_FAILURE(status == media::MEDIA_CODEC_OK, |
| 432 "CopyFromOutputBuffer failed", kPlatformFailureError); | 414 "CopyFromOutputBuffer failed", kPlatformFailureError); |
| 433 media_codec_->ReleaseOutputBuffer(buf_index, false); | 415 media_codec_->ReleaseOutputBuffer(buf_index, false); |
| 434 --num_buffers_at_codec_; | 416 --num_buffers_at_codec_; |
| 435 | 417 |
| 436 UMA_HISTOGRAM_COUNTS_10000("Media.AVEA.EncodedBufferSizeKB", size / 1024); | |
| 437 base::MessageLoop::current()->PostTask( | 418 base::MessageLoop::current()->PostTask( |
| 438 FROM_HERE, | 419 FROM_HERE, |
| 439 base::Bind(&VideoEncodeAccelerator::Client::BitstreamBufferReady, | 420 base::Bind(&VideoEncodeAccelerator::Client::BitstreamBufferReady, |
| 440 client_ptr_factory_->GetWeakPtr(), | 421 client_ptr_factory_->GetWeakPtr(), bitstream_buffer.id(), size, |
| 441 bitstream_buffer.id(), | |
| 442 size, | |
| 443 key_frame)); | 422 key_frame)); |
| 444 } | 423 } |
| 445 | 424 |
| 446 } // namespace content | 425 } // namespace media |
| OLD | NEW |