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

Side by Side Diff: media/filters/fake_video_decoder.cc

Issue 239893002: Allow multiple concurrent Decode() requests in VideoDecoder interface. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 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 | Annotate | Revision Log
OLDNEW
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/filters/fake_video_decoder.h" 5 #include "media/filters/fake_video_decoder.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback_helpers.h" 8 #include "base/callback_helpers.h"
9 #include "base/location.h" 9 #include "base/location.h"
10 #include "base/message_loop/message_loop_proxy.h" 10 #include "base/message_loop/message_loop_proxy.h"
11 #include "media/base/bind_to_current_loop.h" 11 #include "media/base/bind_to_current_loop.h"
12 #include "media/base/test_helpers.h" 12 #include "media/base/test_helpers.h"
13 13
14 namespace media { 14 namespace media {
15 15
16 FakeVideoDecoder::FakeVideoDecoder(int decoding_delay, 16 FakeVideoDecoder::FakeVideoDecoder(int decoding_delay,
17 bool supports_get_decode_output) 17 bool supports_get_decode_output,
18 : task_runner_(base::MessageLoopProxy::current()), 18 int max_parallel_decoding_requests)
19 decoding_delay_(decoding_delay), 19 : decoding_delay_(decoding_delay),
20 supports_get_decode_output_(supports_get_decode_output), 20 supports_get_decode_output_(supports_get_decode_output),
21 max_parallel_decoding_requests_(max_parallel_decoding_requests),
21 state_(UNINITIALIZED), 22 state_(UNINITIALIZED),
23 hold_decode_(false),
22 total_bytes_decoded_(0), 24 total_bytes_decoded_(0),
23 weak_factory_(this) { 25 weak_factory_(this) {
24 DCHECK_GE(decoding_delay, 0); 26 DCHECK_GE(decoding_delay, 0);
25 } 27 }
26 28
27 FakeVideoDecoder::~FakeVideoDecoder() { 29 FakeVideoDecoder::~FakeVideoDecoder() {
28 DCHECK_EQ(state_, UNINITIALIZED); 30 DCHECK_EQ(state_, UNINITIALIZED);
29 } 31 }
30 32
31 void FakeVideoDecoder::Initialize(const VideoDecoderConfig& config, 33 void FakeVideoDecoder::Initialize(const VideoDecoderConfig& config,
32 const PipelineStatusCB& status_cb) { 34 const PipelineStatusCB& status_cb) {
33 DCHECK(task_runner_->BelongsToCurrentThread()); 35 DCHECK(thread_checker_.CalledOnValidThread());
34 DCHECK(config.IsValidConfig()); 36 DCHECK(config.IsValidConfig());
35 DCHECK(decode_cb_.IsNull()) << "No reinitialization during pending decode."; 37 DCHECK(held_decode_callbacks_.empty())
38 << "No reinitialization during pending decode.";
36 DCHECK(reset_cb_.IsNull()) << "No reinitialization during pending reset."; 39 DCHECK(reset_cb_.IsNull()) << "No reinitialization during pending reset.";
37 40
38 current_config_ = config; 41 current_config_ = config;
39 init_cb_.SetCallback(BindToCurrentLoop(status_cb)); 42 init_cb_.SetCallback(BindToCurrentLoop(status_cb));
40 43
41 if (!decoded_frames_.empty()) { 44 if (!decoded_frames_.empty()) {
42 DVLOG(1) << "Decoded frames dropped during reinitialization."; 45 DVLOG(1) << "Decoded frames dropped during reinitialization.";
43 decoded_frames_.clear(); 46 decoded_frames_.clear();
44 } 47 }
45 48
46 state_ = NORMAL; 49 state_ = NORMAL;
47 init_cb_.RunOrHold(PIPELINE_OK); 50 init_cb_.RunOrHold(PIPELINE_OK);
48 } 51 }
49 52
50 void FakeVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, 53 void FakeVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
51 const DecodeCB& decode_cb) { 54 const DecodeCB& decode_cb) {
52 DCHECK(task_runner_->BelongsToCurrentThread()); 55 DCHECK(thread_checker_.CalledOnValidThread());
53 DCHECK(decode_cb_.IsNull()) << "Overlapping decodes are not supported.";
54 DCHECK(reset_cb_.IsNull()); 56 DCHECK(reset_cb_.IsNull());
55 DCHECK_LE(decoded_frames_.size(), static_cast<size_t>(decoding_delay_)); 57 DCHECK_LE(decoded_frames_.size(),
58 decoding_delay_ + max_parallel_decoding_requests_);
xhwang 2014/05/01 17:40:35 s/max_parallel_decoding_requests_/held_decode_call
Sergey Ulanov 2014/05/02 02:25:53 Done.
59 DCHECK_LT(static_cast<int>(held_decode_callbacks_.size()),
60 max_parallel_decoding_requests_);
56 61
57 int buffer_size = buffer->end_of_stream() ? 0 : buffer->data_size(); 62 int buffer_size = buffer->end_of_stream() ? 0 : buffer->data_size();
58 decode_cb_.SetCallback( 63 DecodeCB wrapped_decode_cb =
59 BindToCurrentLoop(base::Bind(&FakeVideoDecoder::OnFrameDecoded, 64 BindToCurrentLoop(base::Bind(&FakeVideoDecoder::OnFrameDecoded,
60 weak_factory_.GetWeakPtr(), 65 weak_factory_.GetWeakPtr(),
61 buffer_size, 66 buffer_size,
62 decode_cb))); 67 decode_cb));
63 68
64 if (buffer->end_of_stream() && decoded_frames_.empty()) { 69 if (state_ == ERROR) {
65 decode_cb_.RunOrHold(kOk, VideoFrame::CreateEOSFrame()); 70 wrapped_decode_cb.Run(kDecodeError, scoped_refptr<VideoFrame>());
66 return; 71 return;
67 } 72 }
68 73
69 if (!buffer->end_of_stream()) { 74 if (buffer->end_of_stream()) {
75 state_ = END_OF_STREAM;
76 } else {
70 DCHECK(VerifyFakeVideoBufferForTest(buffer, current_config_)); 77 DCHECK(VerifyFakeVideoBufferForTest(buffer, current_config_));
71 scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateColorFrame( 78 scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateColorFrame(
72 current_config_.coded_size(), 0, 0, 0, buffer->timestamp()); 79 current_config_.coded_size(), 0, 0, 0, buffer->timestamp());
73 decoded_frames_.push_back(video_frame); 80 decoded_frames_.push_back(video_frame);
74
75 if (decoded_frames_.size() <= static_cast<size_t>(decoding_delay_)) {
76 decode_cb_.RunOrHold(kNotEnoughData, scoped_refptr<VideoFrame>());
77 return;
78 }
79 } 81 }
80 82
81 scoped_refptr<VideoFrame> frame = decoded_frames_.front(); 83 RunOrHoldDecode(wrapped_decode_cb);
82 decoded_frames_.pop_front();
83 decode_cb_.RunOrHold(kOk, frame);
84 } 84 }
85 85
86 void FakeVideoDecoder::Reset(const base::Closure& closure) { 86 void FakeVideoDecoder::Reset(const base::Closure& closure) {
87 DCHECK(task_runner_->BelongsToCurrentThread()); 87 DCHECK(thread_checker_.CalledOnValidThread());
88 DCHECK(reset_cb_.IsNull()); 88 DCHECK(reset_cb_.IsNull());
89
89 reset_cb_.SetCallback(BindToCurrentLoop(closure)); 90 reset_cb_.SetCallback(BindToCurrentLoop(closure));
91 decoded_frames_.clear();
90 92
91 // Defer the reset if a decode is pending. 93 // Defer the reset if a decode is pending.
92 if (!decode_cb_.IsNull()) 94 if (!held_decode_callbacks_.empty())
93 return; 95 return;
94 96
95 DoReset(); 97 DoReset();
96 } 98 }
97 99
98 void FakeVideoDecoder::Stop() { 100 void FakeVideoDecoder::Stop() {
99 DCHECK(task_runner_->BelongsToCurrentThread()); 101 DCHECK(thread_checker_.CalledOnValidThread());
100 102
101 if (!init_cb_.IsNull()) 103 if (!init_cb_.IsNull())
102 SatisfyInit(); 104 SatisfyInit();
103 if (!decode_cb_.IsNull()) 105 if (!held_decode_callbacks_.empty())
104 SatisfyDecode(); 106 SatisfyDecode();
105 if (!reset_cb_.IsNull()) 107 if (!reset_cb_.IsNull())
106 SatisfyReset(); 108 SatisfyReset();
107 109
108 decoded_frames_.clear(); 110 decoded_frames_.clear();
109 state_ = UNINITIALIZED; 111 state_ = UNINITIALIZED;
110 } 112 }
111 113
112 scoped_refptr<VideoFrame> FakeVideoDecoder::GetDecodeOutput() { 114 scoped_refptr<VideoFrame> FakeVideoDecoder::GetDecodeOutput() {
113 DCHECK(task_runner_->BelongsToCurrentThread()); 115 DCHECK(thread_checker_.CalledOnValidThread());
114 if (!supports_get_decode_output_ || decoded_frames_.empty()) 116 if (!supports_get_decode_output_ || decoded_frames_.empty())
115 return NULL; 117 return NULL;
116 scoped_refptr<VideoFrame> out = decoded_frames_.front(); 118 scoped_refptr<VideoFrame> out = decoded_frames_.front();
117 decoded_frames_.pop_front(); 119 decoded_frames_.pop_front();
118 return out; 120 return out;
119 } 121 }
120 122
121 void FakeVideoDecoder::HoldNextInit() { 123 void FakeVideoDecoder::HoldNextInit() {
122 DCHECK(task_runner_->BelongsToCurrentThread()); 124 DCHECK(thread_checker_.CalledOnValidThread());
123 init_cb_.HoldCallback(); 125 init_cb_.HoldCallback();
124 } 126 }
125 127
126 void FakeVideoDecoder::HoldNextDecode() { 128 void FakeVideoDecoder::HoldDecode() {
127 DCHECK(task_runner_->BelongsToCurrentThread()); 129 DCHECK(thread_checker_.CalledOnValidThread());
128 decode_cb_.HoldCallback(); 130 hold_decode_ = true;
129 } 131 }
130 132
131 void FakeVideoDecoder::HoldNextReset() { 133 void FakeVideoDecoder::HoldNextReset() {
132 DCHECK(task_runner_->BelongsToCurrentThread()); 134 DCHECK(thread_checker_.CalledOnValidThread());
133 reset_cb_.HoldCallback(); 135 reset_cb_.HoldCallback();
134 } 136 }
135 137
136 void FakeVideoDecoder::SatisfyInit() { 138 void FakeVideoDecoder::SatisfyInit() {
137 DCHECK(task_runner_->BelongsToCurrentThread()); 139 DCHECK(thread_checker_.CalledOnValidThread());
138 DCHECK(decode_cb_.IsNull()); 140 DCHECK(held_decode_callbacks_.empty());
139 DCHECK(reset_cb_.IsNull()); 141 DCHECK(reset_cb_.IsNull());
140 142
141 init_cb_.RunHeldCallback(); 143 init_cb_.RunHeldCallback();
142 } 144 }
143 145
144 void FakeVideoDecoder::SatisfyDecode() { 146 void FakeVideoDecoder::SatisfyDecode() {
145 DCHECK(task_runner_->BelongsToCurrentThread()); 147 DCHECK(thread_checker_.CalledOnValidThread());
146 decode_cb_.RunHeldCallback(); 148 DCHECK_NE(hold_decode_, 0);
147 149
148 if (!reset_cb_.IsNull()) 150 hold_decode_ = 0;
151
152 while (!held_decode_callbacks_.empty()) {
153 SatisfySingleDecode();
154 }
155 }
156
157 void FakeVideoDecoder::SatisfySingleDecode() {
xhwang 2014/05/01 17:40:35 We need to add tests to cover SatisfySingleDecode(
Sergey Ulanov 2014/05/02 02:25:53 Done. Thanks for writing the test for me :)
158 DCHECK(thread_checker_.CalledOnValidThread());
159 DCHECK(!held_decode_callbacks_.empty());
160
161 DecodeCB decode_cb = held_decode_callbacks_.front();
162 held_decode_callbacks_.pop_front();
163 RunDecodeCallback(decode_cb);
164
165 if (!reset_cb_.IsNull() && held_decode_callbacks_.empty())
149 DoReset(); 166 DoReset();
150 } 167 }
151 168
152 void FakeVideoDecoder::SatisfyReset() { 169 void FakeVideoDecoder::SatisfyReset() {
153 DCHECK(task_runner_->BelongsToCurrentThread()); 170 DCHECK(thread_checker_.CalledOnValidThread());
154 DCHECK(decode_cb_.IsNull()); 171 DCHECK(held_decode_callbacks_.empty());
155 reset_cb_.RunHeldCallback(); 172 reset_cb_.RunHeldCallback();
156 } 173 }
157 174
158 void FakeVideoDecoder::DoReset() { 175 void FakeVideoDecoder::SimulateError() {
159 DCHECK(task_runner_->BelongsToCurrentThread()); 176 DCHECK(thread_checker_.CalledOnValidThread());
160 DCHECK(decode_cb_.IsNull());
161 DCHECK(!reset_cb_.IsNull());
162 177
178 state_ = ERROR;
179 while (!held_decode_callbacks_.empty()) {
180 held_decode_callbacks_.front().Run(kDecodeError,
181 scoped_refptr<VideoFrame>());
182 held_decode_callbacks_.pop_front();
183 }
163 decoded_frames_.clear(); 184 decoded_frames_.clear();
164 reset_cb_.RunOrHold(); 185 }
186
187 int FakeVideoDecoder::GetMaxDecodeRequests() const {
188 return max_parallel_decoding_requests_;
165 } 189 }
166 190
167 void FakeVideoDecoder::OnFrameDecoded( 191 void FakeVideoDecoder::OnFrameDecoded(
168 int buffer_size, 192 int buffer_size,
169 const DecodeCB& decode_cb, 193 const DecodeCB& decode_cb,
170 Status status, 194 Status status,
171 const scoped_refptr<VideoFrame>& video_frame) { 195 const scoped_refptr<VideoFrame>& video_frame) {
196 DCHECK(thread_checker_.CalledOnValidThread());
197
172 if (status == kOk || status == kNotEnoughData) 198 if (status == kOk || status == kNotEnoughData)
173 total_bytes_decoded_ += buffer_size; 199 total_bytes_decoded_ += buffer_size;
174 decode_cb.Run(status, video_frame); 200 decode_cb.Run(status, video_frame);
175 } 201 }
176 202
203 void FakeVideoDecoder::RunOrHoldDecode(const DecodeCB& decode_cb) {
204 DCHECK(thread_checker_.CalledOnValidThread());
205
206 if (hold_decode_) {
207 held_decode_callbacks_.push_back(decode_cb);
208 } else {
209 DCHECK(held_decode_callbacks_.empty());
210 RunDecodeCallback(decode_cb);
211 }
212 }
213
214 void FakeVideoDecoder::RunDecodeCallback(const DecodeCB& decode_cb) {
215 DCHECK(thread_checker_.CalledOnValidThread());
216
217 if (!reset_cb_.IsNull()) {
218 DCHECK(decoded_frames_.empty());
219 decode_cb.Run(kAborted, scoped_refptr<VideoFrame>());
220 return;
221 }
222
223 // Make sure we leave decoding_delay_ frames in the queue and also frames for
224 // all pending decode callbacks, except the current one.
225 if (decoded_frames_.size() <=
226 decoding_delay_ + held_decode_callbacks_.size() &&
227 state_ != END_OF_STREAM) {
228 decode_cb.Run(kNotEnoughData, scoped_refptr<VideoFrame>());
229 return;
230 }
231
232 scoped_refptr<VideoFrame> frame;
233 if (decoded_frames_.empty()) {
234 DCHECK_EQ(state_, END_OF_STREAM);
235 frame = VideoFrame::CreateEOSFrame();
236 } else {
237 frame = decoded_frames_.front();
238 decoded_frames_.pop_front();
239 }
240 decode_cb.Run(kOk, frame);
241 }
242
243 void FakeVideoDecoder::DoReset() {
244 DCHECK(thread_checker_.CalledOnValidThread());
245 DCHECK(held_decode_callbacks_.empty());
246 DCHECK(!reset_cb_.IsNull());
247
248 reset_cb_.RunOrHold();
249 }
250
177 } // namespace media 251 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698