| 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 "content/common/gpu/media/android_video_encode_accelerator.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 | 26 |
| 27 namespace content { | 27 namespace content { |
| 28 | 28 |
| 29 enum { | 29 enum { |
| 30 // Subset of MediaCodecInfo.CodecCapabilities. | 30 // Subset of MediaCodecInfo.CodecCapabilities. |
| 31 COLOR_FORMAT_YUV420_SEMIPLANAR = 21, | 31 COLOR_FORMAT_YUV420_SEMIPLANAR = 21, |
| 32 }; | 32 }; |
| 33 | 33 |
| 34 // Helper macros for dealing with failure. If |result| evaluates false, emit | 34 // Helper macros for dealing with failure. If |result| evaluates false, emit |
| 35 // |log| to DLOG(ERROR), register |error| with the client, and return. | 35 // |log| to DLOG(ERROR), register |error| with the client, and return. |
| 36 #define RETURN_ON_FAILURE(result, log, error) \ | 36 #define RETURN_ON_FAILURE(result, log, error) \ |
| 37 do { \ | 37 do { \ |
| 38 if (!(result)) { \ | 38 if (!(result)) { \ |
| 39 DLOG(ERROR) << log; \ | 39 DLOG(ERROR) << log; \ |
| 40 if (client_ptr_factory_.GetWeakPtr()) { \ | 40 if (client_ptr_factory_->GetWeakPtr()) { \ |
| 41 client_ptr_factory_.GetWeakPtr()->NotifyError(error); \ | 41 client_ptr_factory_->GetWeakPtr()->NotifyError(error); \ |
| 42 client_ptr_factory_.InvalidateWeakPtrs(); \ | 42 client_ptr_factory_.reset(); \ |
| 43 } \ | 43 } \ |
| 44 return; \ | 44 return; \ |
| 45 } \ | 45 } \ |
| 46 } while (0) | 46 } while (0) |
| 47 | 47 |
| 48 // Because MediaCodec is thread-hostile (must be poked on a single thread) and | 48 // Because MediaCodec is thread-hostile (must be poked on a single thread) and |
| 49 // has no callback mechanism (b/11990118), we must drive it by polling for | 49 // has no callback mechanism (b/11990118), we must drive it by polling for |
| 50 // complete frames (and available input buffers, when the codec is fully | 50 // complete frames (and available input buffers, when the codec is fully |
| 51 // saturated). This function defines the polling delay. The value used is an | 51 // saturated). This function defines the polling delay. The value used is an |
| 52 // arbitrary choice that trades off CPU utilization (spinning) against latency. | 52 // arbitrary choice that trades off CPU utilization (spinning) against latency. |
| 53 // Mirrors android_video_decode_accelerator.cc::DecodePollDelay(). | 53 // Mirrors android_video_decode_accelerator.cc::DecodePollDelay(). |
| 54 static inline const base::TimeDelta EncodePollDelay() { | 54 static inline const base::TimeDelta EncodePollDelay() { |
| 55 // An alternative to this polling scheme could be to dedicate a new thread | 55 // An alternative to this polling scheme could be to dedicate a new thread |
| 56 // (instead of using the ChildThread) to run the MediaCodec, and make that | 56 // (instead of using the ChildThread) to run the MediaCodec, and make that |
| 57 // thread use the timeout-based flavor of MediaCodec's dequeue methods when it | 57 // thread use the timeout-based flavor of MediaCodec's dequeue methods when it |
| 58 // believes the codec should complete "soon" (e.g. waiting for an input | 58 // believes the codec should complete "soon" (e.g. waiting for an input |
| 59 // buffer, or waiting for a picture when it knows enough complete input | 59 // buffer, or waiting for a picture when it knows enough complete input |
| 60 // pictures have been fed to saturate any internal buffering). This is | 60 // pictures have been fed to saturate any internal buffering). This is |
| 61 // speculative and it's unclear that this would be a win (nor that there's a | 61 // speculative and it's unclear that this would be a win (nor that there's a |
| 62 // reasonably device-agnostic way to fill in the "believes" above). | 62 // reasonably device-agnostic way to fill in the "believes" above). |
| 63 return base::TimeDelta::FromMilliseconds(10); | 63 return base::TimeDelta::FromMilliseconds(10); |
| 64 } | 64 } |
| 65 | 65 |
| 66 static inline const base::TimeDelta NoWaitTimeOut() { | 66 static inline const base::TimeDelta NoWaitTimeOut() { |
| 67 return base::TimeDelta::FromMicroseconds(0); | 67 return base::TimeDelta::FromMicroseconds(0); |
| 68 } | 68 } |
| 69 | 69 |
| 70 AndroidVideoEncodeAccelerator::AndroidVideoEncodeAccelerator( | 70 AndroidVideoEncodeAccelerator::AndroidVideoEncodeAccelerator() |
| 71 media::VideoEncodeAccelerator::Client* client) | 71 : num_buffers_at_codec_(0), |
| 72 : client_ptr_factory_(client), | |
| 73 num_buffers_at_codec_(0), | |
| 74 num_output_buffers_(-1), | 72 num_output_buffers_(-1), |
| 75 output_buffers_capacity_(0), | 73 output_buffers_capacity_(0), |
| 76 last_set_bitrate_(0) {} | 74 last_set_bitrate_(0) {} |
| 77 | 75 |
| 78 AndroidVideoEncodeAccelerator::~AndroidVideoEncodeAccelerator() { | 76 AndroidVideoEncodeAccelerator::~AndroidVideoEncodeAccelerator() { |
| 79 DCHECK(thread_checker_.CalledOnValidThread()); | 77 DCHECK(thread_checker_.CalledOnValidThread()); |
| 80 } | 78 } |
| 81 | 79 |
| 82 // static | 80 // static |
| 83 std::vector<media::VideoEncodeAccelerator::SupportedProfile> | 81 std::vector<media::VideoEncodeAccelerator::SupportedProfile> |
| (...skipping 24 matching lines...) Expand all Loading... |
| 108 // reasonable defaults. | 106 // reasonable defaults. |
| 109 profile.max_resolution.SetSize(1920, 1088); | 107 profile.max_resolution.SetSize(1920, 1088); |
| 110 profile.max_framerate.numerator = 30; | 108 profile.max_framerate.numerator = 30; |
| 111 profile.max_framerate.denominator = 1; | 109 profile.max_framerate.denominator = 1; |
| 112 profiles.push_back(profile); | 110 profiles.push_back(profile); |
| 113 } | 111 } |
| 114 return profiles; | 112 return profiles; |
| 115 } | 113 } |
| 116 | 114 |
| 117 void AndroidVideoEncodeAccelerator::Initialize( | 115 void AndroidVideoEncodeAccelerator::Initialize( |
| 116 Client* client, |
| 118 VideoFrame::Format format, | 117 VideoFrame::Format format, |
| 119 const gfx::Size& input_visible_size, | 118 const gfx::Size& input_visible_size, |
| 120 media::VideoCodecProfile output_profile, | 119 media::VideoCodecProfile output_profile, |
| 121 uint32 initial_bitrate) { | 120 uint32 initial_bitrate) { |
| 122 DVLOG(3) << __PRETTY_FUNCTION__ << " format: " << format | 121 DVLOG(3) << __PRETTY_FUNCTION__ << " format: " << format |
| 123 << ", input_visible_size: " << input_visible_size.ToString() | 122 << ", input_visible_size: " << input_visible_size.ToString() |
| 124 << ", output_profile: " << output_profile | 123 << ", output_profile: " << output_profile |
| 125 << ", initial_bitrate: " << initial_bitrate; | 124 << ", initial_bitrate: " << initial_bitrate; |
| 126 DCHECK(!media_codec_); | 125 DCHECK(!media_codec_); |
| 127 DCHECK(thread_checker_.CalledOnValidThread()); | 126 DCHECK(thread_checker_.CalledOnValidThread()); |
| 128 | 127 |
| 128 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); |
| 129 |
| 129 RETURN_ON_FAILURE(media::MediaCodecBridge::IsAvailable() && | 130 RETURN_ON_FAILURE(media::MediaCodecBridge::IsAvailable() && |
| 130 media::MediaCodecBridge::SupportsSetParameters() && | 131 media::MediaCodecBridge::SupportsSetParameters() && |
| 131 format == VideoFrame::I420 && | 132 format == VideoFrame::I420 && |
| 132 output_profile == media::VP8PROFILE_MAIN, | 133 output_profile == media::VP8PROFILE_MAIN, |
| 133 "Unexpected combo: " << format << ", " << output_profile, | 134 "Unexpected combo: " << format << ", " << output_profile, |
| 134 kInvalidArgumentError); | 135 kInvalidArgumentError); |
| 135 | 136 |
| 136 last_set_bitrate_ = initial_bitrate; | 137 last_set_bitrate_ = initial_bitrate; |
| 137 | 138 |
| 138 // Only consider using MediaCodec if it's likely backed by hardware. | 139 // Only consider using MediaCodec if it's likely backed by hardware. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 154 COLOR_FORMAT_YUV420_SEMIPLANAR)); | 155 COLOR_FORMAT_YUV420_SEMIPLANAR)); |
| 155 | 156 |
| 156 RETURN_ON_FAILURE( | 157 RETURN_ON_FAILURE( |
| 157 media_codec_, | 158 media_codec_, |
| 158 "Failed to create/start the codec: " << input_visible_size.ToString(), | 159 "Failed to create/start the codec: " << input_visible_size.ToString(), |
| 159 kPlatformFailureError); | 160 kPlatformFailureError); |
| 160 | 161 |
| 161 base::MessageLoop::current()->PostTask( | 162 base::MessageLoop::current()->PostTask( |
| 162 FROM_HERE, | 163 FROM_HERE, |
| 163 base::Bind(&VideoEncodeAccelerator::Client::NotifyInitializeDone, | 164 base::Bind(&VideoEncodeAccelerator::Client::NotifyInitializeDone, |
| 164 client_ptr_factory_.GetWeakPtr())); | 165 client_ptr_factory_->GetWeakPtr())); |
| 165 | 166 |
| 166 num_output_buffers_ = media_codec_->GetOutputBuffersCount(); | 167 num_output_buffers_ = media_codec_->GetOutputBuffersCount(); |
| 167 output_buffers_capacity_ = media_codec_->GetOutputBuffersCapacity(); | 168 output_buffers_capacity_ = media_codec_->GetOutputBuffersCapacity(); |
| 168 base::MessageLoop::current()->PostTask( | 169 base::MessageLoop::current()->PostTask( |
| 169 FROM_HERE, | 170 FROM_HERE, |
| 170 base::Bind(&VideoEncodeAccelerator::Client::RequireBitstreamBuffers, | 171 base::Bind(&VideoEncodeAccelerator::Client::RequireBitstreamBuffers, |
| 171 client_ptr_factory_.GetWeakPtr(), | 172 client_ptr_factory_->GetWeakPtr(), |
| 172 num_output_buffers_, | 173 num_output_buffers_, |
| 173 input_visible_size, | 174 input_visible_size, |
| 174 output_buffers_capacity_)); | 175 output_buffers_capacity_)); |
| 175 } | 176 } |
| 176 | 177 |
| 177 void AndroidVideoEncodeAccelerator::MaybeStartIOTimer() { | 178 void AndroidVideoEncodeAccelerator::MaybeStartIOTimer() { |
| 178 if (!io_timer_.IsRunning() && | 179 if (!io_timer_.IsRunning() && |
| 179 (num_buffers_at_codec_ > 0 || !pending_frames_.empty())) { | 180 (num_buffers_at_codec_ > 0 || !pending_frames_.empty())) { |
| 180 io_timer_.Start(FROM_HERE, | 181 io_timer_.Start(FROM_HERE, |
| 181 EncodePollDelay(), | 182 EncodePollDelay(), |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 } | 240 } |
| 240 // Note: Android's MediaCodec doesn't allow mid-stream adjustments to | 241 // Note: Android's MediaCodec doesn't allow mid-stream adjustments to |
| 241 // framerate, so we ignore that here. This is OK because Android only uses | 242 // framerate, so we ignore that here. This is OK because Android only uses |
| 242 // the framerate value from MediaFormat during configure() as a proxy for | 243 // the framerate value from MediaFormat during configure() as a proxy for |
| 243 // bitrate, and we set that explicitly. | 244 // bitrate, and we set that explicitly. |
| 244 } | 245 } |
| 245 | 246 |
| 246 void AndroidVideoEncodeAccelerator::Destroy() { | 247 void AndroidVideoEncodeAccelerator::Destroy() { |
| 247 DVLOG(3) << __PRETTY_FUNCTION__; | 248 DVLOG(3) << __PRETTY_FUNCTION__; |
| 248 DCHECK(thread_checker_.CalledOnValidThread()); | 249 DCHECK(thread_checker_.CalledOnValidThread()); |
| 249 client_ptr_factory_.InvalidateWeakPtrs(); | 250 client_ptr_factory_.reset(); |
| 250 if (media_codec_) { | 251 if (media_codec_) { |
| 251 if (io_timer_.IsRunning()) | 252 if (io_timer_.IsRunning()) |
| 252 io_timer_.Stop(); | 253 io_timer_.Stop(); |
| 253 media_codec_->Stop(); | 254 media_codec_->Stop(); |
| 254 } | 255 } |
| 255 delete this; | 256 delete this; |
| 256 } | 257 } |
| 257 | 258 |
| 258 void AndroidVideoEncodeAccelerator::DoIOTask() { | 259 void AndroidVideoEncodeAccelerator::DoIOTask() { |
| 259 QueueInput(); | 260 QueueInput(); |
| 260 DequeueOutput(); | 261 DequeueOutput(); |
| 261 MaybeStartIOTimer(); | 262 MaybeStartIOTimer(); |
| 262 MaybeStopIOTimer(); | 263 MaybeStopIOTimer(); |
| 263 } | 264 } |
| 264 | 265 |
| 265 void AndroidVideoEncodeAccelerator::QueueInput() { | 266 void AndroidVideoEncodeAccelerator::QueueInput() { |
| 266 if (!client_ptr_factory_.GetWeakPtr() || pending_frames_.empty()) | 267 if (!client_ptr_factory_->GetWeakPtr() || pending_frames_.empty()) |
| 267 return; | 268 return; |
| 268 | 269 |
| 269 int input_buf_index = 0; | 270 int input_buf_index = 0; |
| 270 media::MediaCodecStatus status = | 271 media::MediaCodecStatus status = |
| 271 media_codec_->DequeueInputBuffer(NoWaitTimeOut(), &input_buf_index); | 272 media_codec_->DequeueInputBuffer(NoWaitTimeOut(), &input_buf_index); |
| 272 if (status != media::MEDIA_CODEC_OK) { | 273 if (status != media::MEDIA_CODEC_OK) { |
| 273 DCHECK(status == media::MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER || | 274 DCHECK(status == media::MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER || |
| 274 status == media::MEDIA_CODEC_ERROR); | 275 status == media::MEDIA_CODEC_ERROR); |
| 275 RETURN_ON_FAILURE(status != media::MEDIA_CODEC_ERROR, | 276 RETURN_ON_FAILURE(status != media::MEDIA_CODEC_ERROR, |
| 276 "MediaCodec error", | 277 "MediaCodec error", |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 bool ret = media_codec_->GetOutputBuffers() && count <= num_output_buffers_ && | 341 bool ret = media_codec_->GetOutputBuffers() && count <= num_output_buffers_ && |
| 341 capacity <= output_buffers_capacity_; | 342 capacity <= output_buffers_capacity_; |
| 342 LOG_IF(ERROR, !ret) << "Need more/bigger buffers; before: " | 343 LOG_IF(ERROR, !ret) << "Need more/bigger buffers; before: " |
| 343 << num_output_buffers_ << "x" << output_buffers_capacity_ | 344 << num_output_buffers_ << "x" << output_buffers_capacity_ |
| 344 << ", now: " << count << "x" << capacity; | 345 << ", now: " << count << "x" << capacity; |
| 345 UMA_HISTOGRAM_BOOLEAN("Media.AVEA.OutputBuffersSuffice", ret); | 346 UMA_HISTOGRAM_BOOLEAN("Media.AVEA.OutputBuffersSuffice", ret); |
| 346 return ret; | 347 return ret; |
| 347 } | 348 } |
| 348 | 349 |
| 349 void AndroidVideoEncodeAccelerator::DequeueOutput() { | 350 void AndroidVideoEncodeAccelerator::DequeueOutput() { |
| 350 if (!client_ptr_factory_.GetWeakPtr() || | 351 if (!client_ptr_factory_->GetWeakPtr() || |
| 351 available_bitstream_buffers_.empty() || num_buffers_at_codec_ == 0) { | 352 available_bitstream_buffers_.empty() || num_buffers_at_codec_ == 0) { |
| 352 return; | 353 return; |
| 353 } | 354 } |
| 354 | 355 |
| 355 int32 buf_index = 0; | 356 int32 buf_index = 0; |
| 356 size_t offset = 0; | 357 size_t offset = 0; |
| 357 size_t size = 0; | 358 size_t size = 0; |
| 358 bool key_frame = false; | 359 bool key_frame = false; |
| 359 do { | 360 do { |
| 360 media::MediaCodecStatus status = media_codec_->DequeueOutputBuffer( | 361 media::MediaCodecStatus status = media_codec_->DequeueOutputBuffer( |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 398 kPlatformFailureError); | 399 kPlatformFailureError); |
| 399 | 400 |
| 400 media_codec_->CopyFromOutputBuffer(buf_index, offset, shm->memory(), size); | 401 media_codec_->CopyFromOutputBuffer(buf_index, offset, shm->memory(), size); |
| 401 media_codec_->ReleaseOutputBuffer(buf_index, false); | 402 media_codec_->ReleaseOutputBuffer(buf_index, false); |
| 402 --num_buffers_at_codec_; | 403 --num_buffers_at_codec_; |
| 403 | 404 |
| 404 UMA_HISTOGRAM_COUNTS_10000("Media.AVEA.EncodedBufferSizeKB", size / 1024); | 405 UMA_HISTOGRAM_COUNTS_10000("Media.AVEA.EncodedBufferSizeKB", size / 1024); |
| 405 base::MessageLoop::current()->PostTask( | 406 base::MessageLoop::current()->PostTask( |
| 406 FROM_HERE, | 407 FROM_HERE, |
| 407 base::Bind(&VideoEncodeAccelerator::Client::BitstreamBufferReady, | 408 base::Bind(&VideoEncodeAccelerator::Client::BitstreamBufferReady, |
| 408 client_ptr_factory_.GetWeakPtr(), | 409 client_ptr_factory_->GetWeakPtr(), |
| 409 bitstream_buffer.id(), | 410 bitstream_buffer.id(), |
| 410 size, | 411 size, |
| 411 key_frame)); | 412 key_frame)); |
| 412 } | 413 } |
| 413 | 414 |
| 414 } // namespace content | 415 } // namespace content |
| OLD | NEW |