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

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: fixed includes 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
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 constexpr base::TimeDelta kDecodePollDelay =
21 base::TimeDelta::FromMilliseconds(10); 16 base::TimeDelta::FromMilliseconds(10);
22 constexpr base::TimeDelta kNoWaitTimeout = base::TimeDelta::FromMicroseconds(0); 17 constexpr base::TimeDelta kNoWaitTimeout = base::TimeDelta::FromMicroseconds(0);
23 constexpr base::TimeDelta kIdleTimerTimeout = base::TimeDelta::FromSeconds(1); 18 constexpr base::TimeDelta kIdleTimerTimeout = base::TimeDelta::FromSeconds(1);
24 19
25 static inline bool codec_flush_requires_destruction() {
26 // Return true if and only if Flush() isn't supported / doesn't work.
27 // Prior to JellyBean-MR2, flush() had several bugs (b/8125974, b/8347958) so
28 // we have to completely destroy and recreate the codec there.
29 return base::android::BuildInfo::GetInstance()->sdk_int() < 18;
30 }
31
32 MediaCodecLoop::InputData::InputData() {} 20 MediaCodecLoop::InputData::InputData() {}
33 21
34 MediaCodecLoop::InputData::InputData(const InputData& other) 22 MediaCodecLoop::InputData::InputData(const InputData& other)
35 : memory(other.memory), 23 : memory(other.memory),
36 length(other.length), 24 length(other.length),
37 key_id(other.key_id), 25 key_id(other.key_id),
38 iv(other.iv), 26 iv(other.iv),
39 subsamples(other.subsamples), 27 subsamples(other.subsamples),
40 presentation_time(other.presentation_time), 28 presentation_time(other.presentation_time),
41 is_eos(other.is_eos), 29 is_eos(other.is_eos),
42 is_encrypted(other.is_encrypted) {} 30 is_encrypted(other.is_encrypted) {}
43 31
44 MediaCodecLoop::InputData::~InputData() {} 32 MediaCodecLoop::InputData::~InputData() {}
45 33
46 MediaCodecLoop::MediaCodecLoop(Client* client, 34 MediaCodecLoop::MediaCodecLoop(
47 std::unique_ptr<MediaCodecBridge> media_codec) 35 int sdk_int,
36 Client* client,
37 std::unique_ptr<MediaCodecBridge> media_codec,
38 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
48 : state_(STATE_READY), 39 : state_(STATE_READY),
49 client_(client), 40 client_(client),
50 media_codec_(std::move(media_codec)), 41 media_codec_(std::move(media_codec)),
51 pending_input_buf_index_(kInvalidBufferIndex), 42 pending_input_buf_index_(kInvalidBufferIndex),
43 sdk_int_(sdk_int),
52 weak_factory_(this) { 44 weak_factory_(this) {
45 if (task_runner)
46 io_timer_.SetTaskRunner(task_runner);
53 // TODO(liberato): should this DCHECK? 47 // TODO(liberato): should this DCHECK?
54 if (media_codec_ == nullptr) 48 if (media_codec_ == nullptr)
55 SetState(STATE_ERROR); 49 SetState(STATE_ERROR);
56 } 50 }
57 51
58 MediaCodecLoop::~MediaCodecLoop() { 52 MediaCodecLoop::~MediaCodecLoop() {
59 io_timer_.Stop(); 53 io_timer_.Stop();
60 } 54 }
61 55
56 void MediaCodecLoop::SetTestTickClock(base::TickClock* test_tick_clock) {
57 test_tick_clock_ = test_tick_clock;
58 }
59
62 void MediaCodecLoop::OnKeyAdded() { 60 void MediaCodecLoop::OnKeyAdded() {
63 if (state_ == STATE_WAITING_FOR_KEY) 61 if (state_ == STATE_WAITING_FOR_KEY)
64 SetState(STATE_READY); 62 SetState(STATE_READY);
65 63
66 DoPendingWork(); 64 DoPendingWork();
67 } 65 }
68 66
69 bool MediaCodecLoop::TryFlush() { 67 bool MediaCodecLoop::TryFlush() {
70 // We do not clear the input queue here. It depends on the caller. 68 // 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 69 // For decoder reset, then it is appropriate. Otherwise, the requests might
72 // simply be sent to us later, such as on a format change. 70 // simply be sent to us later, such as on a format change.
73 71
74 // STATE_DRAINED seems like it allows flush, but it causes test failures. 72 // STATE_DRAINED seems like it allows flush, but it causes test failures.
75 // crbug.com/624878 73 // crbug.com/624878
76 if (state_ == STATE_ERROR || state_ == STATE_DRAINED) 74 if (state_ == STATE_ERROR || state_ == STATE_DRAINED)
77 return false; 75 return false;
78 76
79 if (codec_flush_requires_destruction()) 77 if (DoesCodecFlushRequireDestruction())
80 return false; 78 return false;
81 79
82 // Actually try to flush! 80 // Actually try to flush!
83 io_timer_.Stop(); 81 io_timer_.Stop();
84 82
85 if (media_codec_->Flush() != MEDIA_CODEC_OK) { 83 if (media_codec_->Flush() != MEDIA_CODEC_OK) {
86 // TODO(liberato): we might not want to notify the client about this. 84 // TODO(liberato): we might not want to notify the client about this.
87 SetState(STATE_ERROR); 85 SetState(STATE_ERROR);
88 return false; 86 return false;
89 } 87 }
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 SetState(STATE_ERROR); 301 SetState(STATE_ERROR);
304 break; 302 break;
305 } 303 }
306 304
307 return did_work; 305 return did_work;
308 } 306 }
309 307
310 void MediaCodecLoop::ManageTimer(bool did_work) { 308 void MediaCodecLoop::ManageTimer(bool did_work) {
311 bool should_be_running = true; 309 bool should_be_running = true;
312 310
313 base::TimeTicks now = base::TimeTicks::Now(); 311 // One might also use DefaultTickClock, but then ownership becomes harder.
312 base::TimeTicks now = (test_tick_clock_ ? test_tick_clock_->NowTicks()
DaleCurtis 2016/08/01 18:23:16 Instead of doing this, always create tick_clock_.
313 : base::TimeTicks::Now());
314 if (did_work || idle_time_begin_ == base::TimeTicks()) { 314 if (did_work || idle_time_begin_ == base::TimeTicks()) {
315 idle_time_begin_ = now; 315 idle_time_begin_ = now;
316 } else { 316 } else {
317 // Make sure that we have done work recently enough, else stop the timer. 317 // Make sure that we have done work recently enough, else stop the timer.
318 if (now - idle_time_begin_ > kIdleTimerTimeout) 318 if (now - idle_time_begin_ > kIdleTimerTimeout)
319 should_be_running = false; 319 should_be_running = false;
320 } 320 }
321 321
322 if (should_be_running && !io_timer_.IsRunning()) { 322 if (should_be_running && !io_timer_.IsRunning()) {
323 io_timer_.Start(FROM_HERE, kDecodePollDelay, this, 323 io_timer_.Start(FROM_HERE, kDecodePollDelay, this,
324 &MediaCodecLoop::DoPendingWork); 324 &MediaCodecLoop::DoPendingWork);
325 } else if (!should_be_running && io_timer_.IsRunning()) { 325 } else if (!should_be_running && io_timer_.IsRunning()) {
326 io_timer_.Stop(); 326 io_timer_.Stop();
327 } 327 }
328 } 328 }
329 329
330 void MediaCodecLoop::SetState(State new_state) { 330 void MediaCodecLoop::SetState(State new_state) {
331 const State old_state = state_; 331 const State old_state = state_;
332 state_ = new_state; 332 state_ = new_state;
333 if (old_state != new_state && new_state == STATE_ERROR) 333 if (old_state != new_state && new_state == STATE_ERROR)
334 client_->OnCodecLoopError(); 334 client_->OnCodecLoopError();
335 } 335 }
336 336
337 MediaCodecBridge* MediaCodecLoop::GetCodec() const { 337 MediaCodecBridge* MediaCodecLoop::GetCodec() const {
338 return media_codec_.get(); 338 return media_codec_.get();
339 } 339 }
340 340
341 bool MediaCodecLoop::DoesCodecFlushRequireDestruction() const {
342 // Return true if and only if Flush() isn't supported / doesn't work.
343 // Prior to JellyBean-MR2, flush() had several bugs (b/8125974, b/8347958) so
344 // we have to completely destroy and recreate the codec there.
345 return sdk_int_ < 18;
346 }
347
341 // static 348 // static
342 const char* MediaCodecLoop::AsString(State state) { 349 const char* MediaCodecLoop::AsString(State state) {
343 #define RETURN_STRING(x) \ 350 #define RETURN_STRING(x) \
344 case x: \ 351 case x: \
345 return #x; 352 return #x;
346 353
347 switch (state) { 354 switch (state) {
348 RETURN_STRING(STATE_READY); 355 RETURN_STRING(STATE_READY);
349 RETURN_STRING(STATE_WAITING_FOR_KEY); 356 RETURN_STRING(STATE_WAITING_FOR_KEY);
350 RETURN_STRING(STATE_DRAINING); 357 RETURN_STRING(STATE_DRAINING);
351 RETURN_STRING(STATE_DRAINED); 358 RETURN_STRING(STATE_DRAINED);
352 RETURN_STRING(STATE_ERROR); 359 RETURN_STRING(STATE_ERROR);
353 } 360 }
354 #undef RETURN_STRING 361 #undef RETURN_STRING
355 362
356 NOTREACHED() << "Unknown state " << state; 363 NOTREACHED() << "Unknown state " << state;
357 return nullptr; 364 return nullptr;
358 } 365 }
359 366
360 } // namespace media 367 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698