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

Side by Side Diff: media/base/android/media_codec_loop.cc

Issue 2132653002: MediaCodecLoop unit tests (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: cl feedback Created 4 years, 4 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/base/android/media_codec_loop.h ('k') | media/base/android/media_codec_loop_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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/base/android/media_codec_loop.h" 5 #include "media/base/android/media_codec_loop.h"
6 6
7 #include "base/android/build_info.h"
8 #include "base/bind.h" 7 #include "base/bind.h"
9 #include "base/callback_helpers.h" 8 #include "base/callback_helpers.h"
10 #include "base/logging.h" 9 #include "base/logging.h"
11 #include "base/threading/thread_task_runner_handle.h"
12 #include "media/base/android/sdk_media_codec_bridge.h"
13 #include "media/base/audio_buffer.h"
14 #include "media/base/audio_timestamp_helper.h"
15 #include "media/base/bind_to_current_loop.h" 10 #include "media/base/bind_to_current_loop.h"
16 #include "media/base/timestamp_constants.h" 11 #include "media/base/timestamp_constants.h"
17 12
18 namespace media { 13 namespace media {
19 14
20 constexpr base::TimeDelta kDecodePollDelay = 15 // Declaring these as constexpr variables doesn't work in windows -- they
21 base::TimeDelta::FromMilliseconds(10); 16 // always are 0. The exception is FromMicroseconds, which doesn't do any
22 constexpr base::TimeDelta kNoWaitTimeout = base::TimeDelta::FromMicroseconds(0); 17 // conversion. However, declaring these as constexpr functions seesm to work
23 constexpr base::TimeDelta kIdleTimerTimeout = base::TimeDelta::FromSeconds(1); 18 // fine everywhere. We care that this works in windows because our unit tests
19 // run on non-android platforms.
20 constexpr base::TimeDelta DecodePollDelay() {
21 return base::TimeDelta::FromMilliseconds(10);
22 }
24 23
25 static inline bool codec_flush_requires_destruction() { 24 constexpr base::TimeDelta NoWaitTimeout() {
26 // Return true if and only if Flush() isn't supported / doesn't work. 25 return base::TimeDelta::FromMicroseconds(0);
27 // Prior to JellyBean-MR2, flush() had several bugs (b/8125974, b/8347958) so 26 }
28 // we have to completely destroy and recreate the codec there. 27
29 return base::android::BuildInfo::GetInstance()->sdk_int() < 18; 28 constexpr base::TimeDelta IdleTimerTimeout() {
29 return base::TimeDelta::FromSeconds(1);
30 } 30 }
31 31
32 MediaCodecLoop::InputData::InputData() {} 32 MediaCodecLoop::InputData::InputData() {}
33 33
34 MediaCodecLoop::InputData::InputData(const InputData& other) 34 MediaCodecLoop::InputData::InputData(const InputData& other)
35 : memory(other.memory), 35 : memory(other.memory),
36 length(other.length), 36 length(other.length),
37 key_id(other.key_id), 37 key_id(other.key_id),
38 iv(other.iv), 38 iv(other.iv),
39 subsamples(other.subsamples), 39 subsamples(other.subsamples),
40 presentation_time(other.presentation_time), 40 presentation_time(other.presentation_time),
41 is_eos(other.is_eos), 41 is_eos(other.is_eos),
42 is_encrypted(other.is_encrypted) {} 42 is_encrypted(other.is_encrypted) {}
43 43
44 MediaCodecLoop::InputData::~InputData() {} 44 MediaCodecLoop::InputData::~InputData() {}
45 45
46 MediaCodecLoop::MediaCodecLoop(Client* client, 46 MediaCodecLoop::MediaCodecLoop(
47 std::unique_ptr<MediaCodecBridge> media_codec) 47 int sdk_int,
48 Client* client,
49 std::unique_ptr<MediaCodecBridge> media_codec,
50 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
48 : state_(STATE_READY), 51 : state_(STATE_READY),
49 client_(client), 52 client_(client),
50 media_codec_(std::move(media_codec)), 53 media_codec_(std::move(media_codec)),
51 pending_input_buf_index_(kInvalidBufferIndex), 54 pending_input_buf_index_(kInvalidBufferIndex),
55 sdk_int_(sdk_int),
52 weak_factory_(this) { 56 weak_factory_(this) {
57 if (task_runner)
58 io_timer_.SetTaskRunner(task_runner);
53 // TODO(liberato): should this DCHECK? 59 // TODO(liberato): should this DCHECK?
54 if (media_codec_ == nullptr) 60 if (media_codec_ == nullptr)
55 SetState(STATE_ERROR); 61 SetState(STATE_ERROR);
56 } 62 }
57 63
58 MediaCodecLoop::~MediaCodecLoop() { 64 MediaCodecLoop::~MediaCodecLoop() {
59 io_timer_.Stop(); 65 io_timer_.Stop();
60 } 66 }
61 67
68 void MediaCodecLoop::SetTestTickClock(base::TickClock* test_tick_clock) {
69 test_tick_clock_ = test_tick_clock;
70 }
71
62 void MediaCodecLoop::OnKeyAdded() { 72 void MediaCodecLoop::OnKeyAdded() {
63 if (state_ == STATE_WAITING_FOR_KEY) 73 if (state_ == STATE_WAITING_FOR_KEY)
64 SetState(STATE_READY); 74 SetState(STATE_READY);
65 75
66 DoPendingWork(); 76 DoPendingWork();
67 } 77 }
68 78
69 bool MediaCodecLoop::TryFlush() { 79 bool MediaCodecLoop::TryFlush() {
70 // We do not clear the input queue here. It depends on the caller. 80 // We do not clear the input queue here. It depends on the caller.
71 // For decoder reset, then it is appropriate. Otherwise, the requests might 81 // For decoder reset, then it is appropriate. Otherwise, the requests might
72 // simply be sent to us later, such as on a format change. 82 // simply be sent to us later, such as on a format change.
73 83
74 // STATE_DRAINED seems like it allows flush, but it causes test failures. 84 // STATE_DRAINED seems like it allows flush, but it causes test failures.
75 // crbug.com/624878 85 // crbug.com/624878
76 if (state_ == STATE_ERROR || state_ == STATE_DRAINED) 86 if (state_ == STATE_ERROR || state_ == STATE_DRAINED)
77 return false; 87 return false;
78 88
79 if (codec_flush_requires_destruction()) 89 if (CodecNeedsFlushWorkaround())
80 return false; 90 return false;
81 91
82 // Actually try to flush! 92 // Actually try to flush!
83 io_timer_.Stop(); 93 io_timer_.Stop();
84 94
85 if (media_codec_->Flush() != MEDIA_CODEC_OK) { 95 if (media_codec_->Flush() != MEDIA_CODEC_OK) {
86 // TODO(liberato): we might not want to notify the client about this. 96 // TODO(liberato): we might not want to notify the client about this.
87 SetState(STATE_ERROR); 97 SetState(STATE_ERROR);
88 return false; 98 return false;
89 } 99 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 // MediaCodec's QueueSecureInputBuffer(). 150 // MediaCodec's QueueSecureInputBuffer().
141 if (pending_input_buf_index_ != kInvalidBufferIndex) { 151 if (pending_input_buf_index_ != kInvalidBufferIndex) {
142 InputBuffer result(pending_input_buf_index_, true); 152 InputBuffer result(pending_input_buf_index_, true);
143 pending_input_buf_index_ = kInvalidBufferIndex; 153 pending_input_buf_index_ = kInvalidBufferIndex;
144 return result; 154 return result;
145 } 155 }
146 156
147 int input_buf_index = kInvalidBufferIndex; 157 int input_buf_index = kInvalidBufferIndex;
148 158
149 media::MediaCodecStatus status = 159 media::MediaCodecStatus status =
150 media_codec_->DequeueInputBuffer(kNoWaitTimeout, &input_buf_index); 160 media_codec_->DequeueInputBuffer(NoWaitTimeout(), &input_buf_index);
151 switch (status) { 161 switch (status) {
152 case media::MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: 162 case media::MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER:
153 break; 163 break;
154 164
155 case media::MEDIA_CODEC_ERROR: 165 case media::MEDIA_CODEC_ERROR:
156 DLOG(ERROR) << __FUNCTION__ 166 DLOG(ERROR) << __FUNCTION__
157 << ": MEDIA_CODEC_ERROR from DequeInputBuffer"; 167 << ": MEDIA_CODEC_ERROR from DequeInputBuffer";
158 SetState(STATE_ERROR); 168 SetState(STATE_ERROR);
159 break; 169 break;
160 170
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 252
243 bool MediaCodecLoop::ProcessOneOutputBuffer() { 253 bool MediaCodecLoop::ProcessOneOutputBuffer() {
244 // TODO(liberato): When merging AVDA, we will also have to ask the client if 254 // TODO(liberato): When merging AVDA, we will also have to ask the client if
245 // it can accept another output buffer. 255 // it can accept another output buffer.
246 256
247 if (state_ == STATE_ERROR) 257 if (state_ == STATE_ERROR)
248 return false; 258 return false;
249 259
250 OutputBuffer out; 260 OutputBuffer out;
251 MediaCodecStatus status = media_codec_->DequeueOutputBuffer( 261 MediaCodecStatus status = media_codec_->DequeueOutputBuffer(
252 kNoWaitTimeout, &out.index, &out.offset, &out.size, &out.pts, &out.is_eos, 262 NoWaitTimeout(), &out.index, &out.offset, &out.size, &out.pts,
253 &out.is_key_frame); 263 &out.is_eos, &out.is_key_frame);
254 264
255 bool did_work = false; 265 bool did_work = false;
256 switch (status) { 266 switch (status) {
257 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: 267 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED:
258 // Output buffers are replaced in MediaCodecBridge, nothing to do. 268 // Output buffers are replaced in MediaCodecBridge, nothing to do.
259 did_work = true; 269 did_work = true;
260 break; 270 break;
261 271
262 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: 272 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
263 if (!client_->OnOutputFormatChanged()) 273 if (!client_->OnOutputFormatChanged())
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 SetState(STATE_ERROR); 313 SetState(STATE_ERROR);
304 break; 314 break;
305 } 315 }
306 316
307 return did_work; 317 return did_work;
308 } 318 }
309 319
310 void MediaCodecLoop::ManageTimer(bool did_work) { 320 void MediaCodecLoop::ManageTimer(bool did_work) {
311 bool should_be_running = true; 321 bool should_be_running = true;
312 322
313 base::TimeTicks now = base::TimeTicks::Now(); 323 // One might also use DefaultTickClock, but then ownership becomes harder.
324 base::TimeTicks now = (test_tick_clock_ ? test_tick_clock_->NowTicks()
325 : base::TimeTicks::Now());
314 if (did_work || idle_time_begin_ == base::TimeTicks()) { 326 if (did_work || idle_time_begin_ == base::TimeTicks()) {
315 idle_time_begin_ = now; 327 idle_time_begin_ = now;
316 } else { 328 } else {
317 // Make sure that we have done work recently enough, else stop the timer. 329 // Make sure that we have done work recently enough, else stop the timer.
318 if (now - idle_time_begin_ > kIdleTimerTimeout) 330 if (now - idle_time_begin_ > IdleTimerTimeout())
319 should_be_running = false; 331 should_be_running = false;
320 } 332 }
321 333
322 if (should_be_running && !io_timer_.IsRunning()) { 334 if (should_be_running && !io_timer_.IsRunning()) {
323 io_timer_.Start(FROM_HERE, kDecodePollDelay, this, 335 io_timer_.Start(FROM_HERE, DecodePollDelay(), this,
324 &MediaCodecLoop::DoPendingWork); 336 &MediaCodecLoop::DoPendingWork);
325 } else if (!should_be_running && io_timer_.IsRunning()) { 337 } else if (!should_be_running && io_timer_.IsRunning()) {
326 io_timer_.Stop(); 338 io_timer_.Stop();
327 } 339 }
328 } 340 }
329 341
330 void MediaCodecLoop::SetState(State new_state) { 342 void MediaCodecLoop::SetState(State new_state) {
331 const State old_state = state_; 343 const State old_state = state_;
332 state_ = new_state; 344 state_ = new_state;
333 if (old_state != new_state && new_state == STATE_ERROR) 345 if (old_state != new_state && new_state == STATE_ERROR)
334 client_->OnCodecLoopError(); 346 client_->OnCodecLoopError();
335 } 347 }
336 348
337 MediaCodecBridge* MediaCodecLoop::GetCodec() const { 349 MediaCodecBridge* MediaCodecLoop::GetCodec() const {
338 return media_codec_.get(); 350 return media_codec_.get();
339 } 351 }
340 352
353 bool MediaCodecLoop::CodecNeedsFlushWorkaround() const {
354 // Return true if and only if Flush() isn't supported / doesn't work.
355 // Prior to JellyBean-MR2, flush() had several bugs (b/8125974, b/8347958) so
356 // we have to completely destroy and recreate the codec there.
357 // TODO(liberato): MediaCodecUtil implements the same function. We should
358 // call that one, except that it doesn't compile outside of android right now.
359 return sdk_int_ < 18;
360 }
361
341 // static 362 // static
342 const char* MediaCodecLoop::AsString(State state) { 363 const char* MediaCodecLoop::AsString(State state) {
343 #define RETURN_STRING(x) \ 364 #define RETURN_STRING(x) \
344 case x: \ 365 case x: \
345 return #x; 366 return #x;
346 367
347 switch (state) { 368 switch (state) {
348 RETURN_STRING(STATE_READY); 369 RETURN_STRING(STATE_READY);
349 RETURN_STRING(STATE_WAITING_FOR_KEY); 370 RETURN_STRING(STATE_WAITING_FOR_KEY);
350 RETURN_STRING(STATE_DRAINING); 371 RETURN_STRING(STATE_DRAINING);
351 RETURN_STRING(STATE_DRAINED); 372 RETURN_STRING(STATE_DRAINED);
352 RETURN_STRING(STATE_ERROR); 373 RETURN_STRING(STATE_ERROR);
353 } 374 }
354 #undef RETURN_STRING 375 #undef RETURN_STRING
355 376
356 NOTREACHED() << "Unknown state " << state; 377 NOTREACHED() << "Unknown state " << state;
357 return nullptr; 378 return nullptr;
358 } 379 }
359 380
360 } // namespace media 381 } // namespace media
OLDNEW
« no previous file with comments | « media/base/android/media_codec_loop.h ('k') | media/base/android/media_codec_loop_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698