Chromium Code Reviews| 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 29 matching lines...) Expand all Loading... | |
| 40 COLOR_FORMAT_YUV420_PLANAR = 19, | 40 COLOR_FORMAT_YUV420_PLANAR = 19, |
| 41 COLOR_FORMAT_YUV420_SEMIPLANAR = 21, | 41 COLOR_FORMAT_YUV420_SEMIPLANAR = 21, |
| 42 }; | 42 }; |
| 43 | 43 |
| 44 // Helper macros for dealing with failure. If |result| evaluates false, emit | 44 // Helper macros for dealing with failure. If |result| evaluates false, emit |
| 45 // |log| to DLOG(ERROR), register |error| with the client, and return. | 45 // |log| to DLOG(ERROR), register |error| with the client, and return. |
| 46 #define RETURN_ON_FAILURE(result, log, error) \ | 46 #define RETURN_ON_FAILURE(result, log, error) \ |
| 47 do { \ | 47 do { \ |
| 48 if (!(result)) { \ | 48 if (!(result)) { \ |
| 49 DLOG(ERROR) << log; \ | 49 DLOG(ERROR) << log; \ |
| 50 if (client_ptr_factory_->GetWeakPtr()) { \ | 50 if (client_ptr_factory_->GetWeakPtr()) { \ |
|
watk
2016/12/28 01:01:51
It's not possible for this to be null AFAICT. Shou
braveyao
2016/12/28 01:28:18
Done.
| |
| 51 client_ptr_factory_->GetWeakPtr()->NotifyError(error); \ | 51 client_ptr_factory_->GetWeakPtr()->NotifyError(error); \ |
| 52 client_ptr_factory_.reset(); \ | |
| 53 } \ | 52 } \ |
| 53 error_occurred_ = true; \ | |
| 54 return; \ | 54 return; \ |
| 55 } \ | 55 } \ |
| 56 } while (0) | 56 } while (0) |
| 57 | 57 |
| 58 // Because MediaCodec is thread-hostile (must be poked on a single thread) and | 58 // Because MediaCodec is thread-hostile (must be poked on a single thread) and |
| 59 // has no callback mechanism (b/11990118), we must drive it by polling for | 59 // has no callback mechanism (b/11990118), we must drive it by polling for |
| 60 // complete frames (and available input buffers, when the codec is fully | 60 // complete frames (and available input buffers, when the codec is fully |
| 61 // saturated). This function defines the polling delay. The value used is an | 61 // saturated). This function defines the polling delay. The value used is an |
| 62 // arbitrary choice that trades off CPU utilization (spinning) against latency. | 62 // arbitrary choice that trades off CPU utilization (spinning) against latency. |
| 63 // Mirrors android_video_decode_accelerator.cc::DecodePollDelay(). | 63 // Mirrors android_video_decode_accelerator.cc::DecodePollDelay(). |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 87 *pixel_format = COLOR_FORMAT_YUV420_SEMIPLANAR; | 87 *pixel_format = COLOR_FORMAT_YUV420_SEMIPLANAR; |
| 88 else if (formats.count(COLOR_FORMAT_YUV420_PLANAR) > 0) | 88 else if (formats.count(COLOR_FORMAT_YUV420_PLANAR) > 0) |
| 89 *pixel_format = COLOR_FORMAT_YUV420_PLANAR; | 89 *pixel_format = COLOR_FORMAT_YUV420_PLANAR; |
| 90 else | 90 else |
| 91 return false; | 91 return false; |
| 92 | 92 |
| 93 return true; | 93 return true; |
| 94 } | 94 } |
| 95 | 95 |
| 96 AndroidVideoEncodeAccelerator::AndroidVideoEncodeAccelerator() | 96 AndroidVideoEncodeAccelerator::AndroidVideoEncodeAccelerator() |
| 97 : num_buffers_at_codec_(0), last_set_bitrate_(0) {} | 97 : num_buffers_at_codec_(0), last_set_bitrate_(0), error_occurred_(false) {} |
| 98 | 98 |
| 99 AndroidVideoEncodeAccelerator::~AndroidVideoEncodeAccelerator() { | 99 AndroidVideoEncodeAccelerator::~AndroidVideoEncodeAccelerator() { |
| 100 DCHECK(thread_checker_.CalledOnValidThread()); | 100 DCHECK(thread_checker_.CalledOnValidThread()); |
| 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 { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 144 VideoCodecProfile output_profile, | 144 VideoCodecProfile output_profile, |
| 145 uint32_t initial_bitrate, | 145 uint32_t initial_bitrate, |
| 146 Client* client) { | 146 Client* client) { |
| 147 DVLOG(3) << __func__ << " format: " << VideoPixelFormatToString(format) | 147 DVLOG(3) << __func__ << " format: " << VideoPixelFormatToString(format) |
| 148 << ", input_visible_size: " << input_visible_size.ToString() | 148 << ", input_visible_size: " << input_visible_size.ToString() |
| 149 << ", output_profile: " << GetProfileName(output_profile) | 149 << ", output_profile: " << GetProfileName(output_profile) |
| 150 << ", initial_bitrate: " << initial_bitrate; | 150 << ", initial_bitrate: " << initial_bitrate; |
| 151 DCHECK(!media_codec_); | 151 DCHECK(!media_codec_); |
| 152 DCHECK(thread_checker_.CalledOnValidThread()); | 152 DCHECK(thread_checker_.CalledOnValidThread()); |
| 153 | 153 |
| 154 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); | 154 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); |
|
watk
2016/12/28 01:01:51
I'd suggest adding a DCHECK(client) or if (!client
braveyao
2016/12/28 01:28:18
Done.
| |
| 155 error_occurred_ = false; | |
|
watk
2016/12/28 01:01:51
Initialize() cannot be called more than once so th
braveyao
2016/12/28 01:28:18
Done.
| |
| 155 | 156 |
| 156 if (!(MediaCodecUtil::SupportsSetParameters() && | 157 if (!(MediaCodecUtil::SupportsSetParameters() && |
| 157 format == PIXEL_FORMAT_I420)) { | 158 format == PIXEL_FORMAT_I420)) { |
| 158 DLOG(ERROR) << "Unexpected combo: " << format << ", " << output_profile; | 159 DLOG(ERROR) << "Unexpected combo: " << format << ", " << output_profile; |
| 159 return false; | 160 return false; |
| 160 } | 161 } |
| 161 | 162 |
| 162 std::string mime_type; | 163 std::string mime_type; |
| 163 VideoCodec codec; | 164 VideoCodec codec; |
| 164 // The client should be prepared to feed at least this many frames into the | 165 // The client should be prepared to feed at least this many frames into the |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 278 // Note: Android's MediaCodec doesn't allow mid-stream adjustments to | 279 // Note: Android's MediaCodec doesn't allow mid-stream adjustments to |
| 279 // framerate, so we ignore that here. This is OK because Android only uses | 280 // framerate, so we ignore that here. This is OK because Android only uses |
| 280 // the framerate value from MediaFormat during configure() as a proxy for | 281 // the framerate value from MediaFormat during configure() as a proxy for |
| 281 // bitrate, and we set that explicitly. | 282 // bitrate, and we set that explicitly. |
| 282 } | 283 } |
| 283 | 284 |
| 284 void AndroidVideoEncodeAccelerator::Destroy() { | 285 void AndroidVideoEncodeAccelerator::Destroy() { |
| 285 DVLOG(3) << __PRETTY_FUNCTION__; | 286 DVLOG(3) << __PRETTY_FUNCTION__; |
| 286 DCHECK(thread_checker_.CalledOnValidThread()); | 287 DCHECK(thread_checker_.CalledOnValidThread()); |
| 287 client_ptr_factory_.reset(); | 288 client_ptr_factory_.reset(); |
| 289 error_occurred_ = false; | |
|
watk
2016/12/28 01:01:51
No need to reset this, we're deleting below. (The
braveyao
2016/12/28 01:28:18
Done.
| |
| 288 if (media_codec_) { | 290 if (media_codec_) { |
| 289 if (io_timer_.IsRunning()) | 291 if (io_timer_.IsRunning()) |
| 290 io_timer_.Stop(); | 292 io_timer_.Stop(); |
| 291 media_codec_->Stop(); | 293 media_codec_->Stop(); |
| 292 } | 294 } |
| 293 delete this; | 295 delete this; |
| 294 } | 296 } |
| 295 | 297 |
| 296 void AndroidVideoEncodeAccelerator::DoIOTask() { | 298 void AndroidVideoEncodeAccelerator::DoIOTask() { |
| 297 QueueInput(); | 299 QueueInput(); |
| 298 DequeueOutput(); | 300 DequeueOutput(); |
| 299 MaybeStartIOTimer(); | 301 MaybeStartIOTimer(); |
| 300 MaybeStopIOTimer(); | 302 MaybeStopIOTimer(); |
| 301 } | 303 } |
| 302 | 304 |
| 303 void AndroidVideoEncodeAccelerator::QueueInput() { | 305 void AndroidVideoEncodeAccelerator::QueueInput() { |
| 304 if (!client_ptr_factory_->GetWeakPtr() || pending_frames_.empty()) | 306 if (error_occurred_ || pending_frames_.empty()) |
| 305 return; | 307 return; |
| 306 | 308 |
| 307 int input_buf_index = 0; | 309 int input_buf_index = 0; |
| 308 MediaCodecStatus status = | 310 MediaCodecStatus status = |
| 309 media_codec_->DequeueInputBuffer(NoWaitTimeOut(), &input_buf_index); | 311 media_codec_->DequeueInputBuffer(NoWaitTimeOut(), &input_buf_index); |
| 310 if (status != MEDIA_CODEC_OK) { | 312 if (status != MEDIA_CODEC_OK) { |
| 311 DCHECK(status == MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER || | 313 DCHECK(status == MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER || |
| 312 status == MEDIA_CODEC_ERROR); | 314 status == MEDIA_CODEC_ERROR); |
| 313 RETURN_ON_FAILURE(status != MEDIA_CODEC_ERROR, "MediaCodec error", | 315 RETURN_ON_FAILURE(status != MEDIA_CODEC_ERROR, "MediaCodec error", |
| 314 kPlatformFailureError); | 316 kPlatformFailureError); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 361 UMA_HISTOGRAM_TIMES("Media.AVDA.InputQueueTime", | 363 UMA_HISTOGRAM_TIMES("Media.AVDA.InputQueueTime", |
| 362 base::Time::Now() - std::get<2>(input)); | 364 base::Time::Now() - std::get<2>(input)); |
| 363 RETURN_ON_FAILURE(status == MEDIA_CODEC_OK, | 365 RETURN_ON_FAILURE(status == MEDIA_CODEC_OK, |
| 364 "Failed to QueueInputBuffer: " << status, | 366 "Failed to QueueInputBuffer: " << status, |
| 365 kPlatformFailureError); | 367 kPlatformFailureError); |
| 366 ++num_buffers_at_codec_; | 368 ++num_buffers_at_codec_; |
| 367 pending_frames_.pop(); | 369 pending_frames_.pop(); |
| 368 } | 370 } |
| 369 | 371 |
| 370 void AndroidVideoEncodeAccelerator::DequeueOutput() { | 372 void AndroidVideoEncodeAccelerator::DequeueOutput() { |
| 371 if (!client_ptr_factory_->GetWeakPtr() || | 373 if (error_occurred_ || available_bitstream_buffers_.empty() || |
| 372 available_bitstream_buffers_.empty() || num_buffers_at_codec_ == 0) { | 374 num_buffers_at_codec_ == 0) { |
| 373 return; | 375 return; |
| 374 } | 376 } |
| 375 | 377 |
| 376 int32_t buf_index = 0; | 378 int32_t buf_index = 0; |
| 377 size_t offset = 0; | 379 size_t offset = 0; |
| 378 size_t size = 0; | 380 size_t size = 0; |
| 379 bool key_frame = false; | 381 bool key_frame = false; |
| 380 | 382 |
| 381 MediaCodecStatus status = | 383 MediaCodecStatus status = |
| 382 media_codec_->DequeueOutputBuffer(NoWaitTimeOut(), &buf_index, &offset, | 384 media_codec_->DequeueOutputBuffer(NoWaitTimeOut(), &buf_index, &offset, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 422 --num_buffers_at_codec_; | 424 --num_buffers_at_codec_; |
| 423 | 425 |
| 424 base::ThreadTaskRunnerHandle::Get()->PostTask( | 426 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 425 FROM_HERE, | 427 FROM_HERE, |
| 426 base::Bind(&VideoEncodeAccelerator::Client::BitstreamBufferReady, | 428 base::Bind(&VideoEncodeAccelerator::Client::BitstreamBufferReady, |
| 427 client_ptr_factory_->GetWeakPtr(), bitstream_buffer.id(), size, | 429 client_ptr_factory_->GetWeakPtr(), bitstream_buffer.id(), size, |
| 428 key_frame, base::Time::Now() - base::Time())); | 430 key_frame, base::Time::Now() - base::Time())); |
| 429 } | 431 } |
| 430 | 432 |
| 431 } // namespace media | 433 } // namespace media |
| OLD | NEW |