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

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, 8 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(
58 decoded_frames_.size(),
59 static_cast<size_t>(decoding_delay_) + max_parallel_decoding_requests_);
60 DCHECK_LT(static_cast<int>(held_decode_callbacks_.size()),
61 max_parallel_decoding_requests_);
56 62
57 int buffer_size = buffer->end_of_stream() ? 0 : buffer->data_size(); 63 int buffer_size = buffer->end_of_stream() ? 0 : buffer->data_size();
58 decode_cb_.SetCallback( 64 DecodeCB wrapped_decode_cb =
59 BindToCurrentLoop(base::Bind(&FakeVideoDecoder::OnFrameDecoded, 65 BindToCurrentLoop(base::Bind(&FakeVideoDecoder::OnFrameDecoded,
60 weak_factory_.GetWeakPtr(), 66 weak_factory_.GetWeakPtr(),
61 buffer_size, 67 buffer_size,
62 decode_cb))); 68 decode_cb));
63 69
64 if (buffer->end_of_stream() && decoded_frames_.empty()) { 70 if (state_ == ERROR) {
65 decode_cb_.RunOrHold(kOk, VideoFrame::CreateEOSFrame()); 71 wrapped_decode_cb.Run(kDecodeError, scoped_refptr<VideoFrame>());
66 return; 72 return;
67 } 73 }
68 74
69 if (!buffer->end_of_stream()) { 75 if (buffer->end_of_stream()) {
76 state_ = END_OF_STREAM;
77 } else {
70 DCHECK(VerifyFakeVideoBufferForTest(buffer, current_config_)); 78 DCHECK(VerifyFakeVideoBufferForTest(buffer, current_config_));
71 scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateColorFrame( 79 scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateColorFrame(
72 current_config_.coded_size(), 0, 0, 0, buffer->timestamp()); 80 current_config_.coded_size(), 0, 0, 0, buffer->timestamp());
73 decoded_frames_.push_back(video_frame); 81 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 } 82 }
80 83
81 scoped_refptr<VideoFrame> frame = decoded_frames_.front(); 84 RunOrHoldDecode(wrapped_decode_cb);
82 decoded_frames_.pop_front();
83 decode_cb_.RunOrHold(kOk, frame);
84 } 85 }
85 86
86 void FakeVideoDecoder::Reset(const base::Closure& closure) { 87 void FakeVideoDecoder::Reset(const base::Closure& closure) {
87 DCHECK(task_runner_->BelongsToCurrentThread()); 88 DCHECK(thread_checker_.CalledOnValidThread());
88 DCHECK(reset_cb_.IsNull()); 89 DCHECK(reset_cb_.IsNull());
90
89 reset_cb_.SetCallback(BindToCurrentLoop(closure)); 91 reset_cb_.SetCallback(BindToCurrentLoop(closure));
92 decoded_frames_.clear();
90 93
91 // Defer the reset if a decode is pending. 94 // Defer the reset if a decode is pending.
92 if (!decode_cb_.IsNull()) 95 if (!held_decode_callbacks_.empty())
93 return; 96 return;
94 97
95 DoReset(); 98 DoReset();
96 } 99 }
97 100
98 void FakeVideoDecoder::Stop() { 101 void FakeVideoDecoder::Stop() {
99 DCHECK(task_runner_->BelongsToCurrentThread()); 102 DCHECK(thread_checker_.CalledOnValidThread());
100 103
101 if (!init_cb_.IsNull()) 104 if (!init_cb_.IsNull())
102 SatisfyInit(); 105 SatisfyInit();
103 if (!decode_cb_.IsNull()) 106 if (!held_decode_callbacks_.empty())
104 SatisfyDecode(); 107 SatisfyDecode();
105 if (!reset_cb_.IsNull()) 108 if (!reset_cb_.IsNull())
106 SatisfyReset(); 109 SatisfyReset();
107 110
108 decoded_frames_.clear(); 111 decoded_frames_.clear();
109 state_ = UNINITIALIZED; 112 state_ = UNINITIALIZED;
110 } 113 }
111 114
112 scoped_refptr<VideoFrame> FakeVideoDecoder::GetDecodeOutput() { 115 scoped_refptr<VideoFrame> FakeVideoDecoder::GetDecodeOutput() {
113 DCHECK(task_runner_->BelongsToCurrentThread()); 116 DCHECK(thread_checker_.CalledOnValidThread());
114 if (!supports_get_decode_output_ || decoded_frames_.empty()) 117 if (!supports_get_decode_output_ || decoded_frames_.empty())
115 return NULL; 118 return NULL;
116 scoped_refptr<VideoFrame> out = decoded_frames_.front(); 119 scoped_refptr<VideoFrame> out = decoded_frames_.front();
117 decoded_frames_.pop_front(); 120 decoded_frames_.pop_front();
118 return out; 121 return out;
119 } 122 }
120 123
121 void FakeVideoDecoder::HoldNextInit() { 124 void FakeVideoDecoder::HoldNextInit() {
122 DCHECK(task_runner_->BelongsToCurrentThread()); 125 DCHECK(thread_checker_.CalledOnValidThread());
123 init_cb_.HoldCallback(); 126 init_cb_.HoldCallback();
124 } 127 }
125 128
126 void FakeVideoDecoder::HoldNextDecode() { 129 void FakeVideoDecoder::HoldDecode() {
127 DCHECK(task_runner_->BelongsToCurrentThread()); 130 DCHECK(thread_checker_.CalledOnValidThread());
128 decode_cb_.HoldCallback(); 131 hold_decode_ = true;
129 } 132 }
130 133
131 void FakeVideoDecoder::HoldNextReset() { 134 void FakeVideoDecoder::HoldNextReset() {
132 DCHECK(task_runner_->BelongsToCurrentThread()); 135 DCHECK(thread_checker_.CalledOnValidThread());
133 reset_cb_.HoldCallback(); 136 reset_cb_.HoldCallback();
134 } 137 }
135 138
136 void FakeVideoDecoder::SatisfyInit() { 139 void FakeVideoDecoder::SatisfyInit() {
137 DCHECK(task_runner_->BelongsToCurrentThread()); 140 DCHECK(thread_checker_.CalledOnValidThread());
138 DCHECK(decode_cb_.IsNull()); 141 DCHECK(held_decode_callbacks_.empty());
139 DCHECK(reset_cb_.IsNull()); 142 DCHECK(reset_cb_.IsNull());
140 143
141 init_cb_.RunHeldCallback(); 144 init_cb_.RunHeldCallback();
142 } 145 }
143 146
144 void FakeVideoDecoder::SatisfyDecode() { 147 void FakeVideoDecoder::SatisfyDecode() {
145 DCHECK(task_runner_->BelongsToCurrentThread()); 148 DCHECK(thread_checker_.CalledOnValidThread());
146 decode_cb_.RunHeldCallback(); 149 DCHECK_NE(hold_decode_, 0);
147 150
148 if (!reset_cb_.IsNull()) 151 hold_decode_ = 0;
152
153 while (!held_decode_callbacks_.empty()) {
154 SatisfySingleDecode();
155 }
156 }
157
158 void FakeVideoDecoder::SatisfySingleDecode() {
159 DCHECK(thread_checker_.CalledOnValidThread());
160 DCHECK(!held_decode_callbacks_.empty());
161
162 RunDecodeCallback(held_decode_callbacks_.front());
163 held_decode_callbacks_.pop_front();
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 {
xhwang 2014/04/25 00:36:03 DCHECK(held_decode_callbacks_.empty()); We should
Sergey Ulanov 2014/04/26 00:59:29 Done.
209 RunDecodeCallback(decode_cb);
210 }
211 }
212
213 void FakeVideoDecoder::RunDecodeCallback(const DecodeCB& decode_cb) {
214 DCHECK(thread_checker_.CalledOnValidThread());
215
216 if (!reset_cb_.IsNull()) {
xhwang 2014/04/25 00:36:03 DCHECK(decoded_frames_.empty());
Sergey Ulanov 2014/04/26 00:59:29 Done.
217 decode_cb.Run(kAborted, scoped_refptr<VideoFrame>());
218 return;
219 }
220 if (static_cast<int>(decoded_frames_.size()) <= decoding_delay_ &&
xhwang 2014/04/25 00:36:03 The two cases we use |decoding_delay_| both involv
Sergey Ulanov 2014/04/26 00:59:29 Done.
221 state_ != END_OF_STREAM) {
222 decode_cb.Run(kNotEnoughData, scoped_refptr<VideoFrame>());
xhwang 2014/04/25 00:36:03 Return early here then we don't need the "else" in
Sergey Ulanov 2014/04/26 00:59:29 Done.
223 } else {
224 scoped_refptr<VideoFrame> frame;
225 if (decoded_frames_.empty()) {
226 DCHECK_EQ(state_, END_OF_STREAM);
227 frame = VideoFrame::CreateEOSFrame();
228 } else {
229 frame = decoded_frames_.front();
230 decoded_frames_.pop_front();
231 }
232 decode_cb.Run(kOk, frame);
233 }
234 }
235
236 void FakeVideoDecoder::DoReset() {
237 DCHECK(thread_checker_.CalledOnValidThread());
238 DCHECK(held_decode_callbacks_.empty());
239 DCHECK(!reset_cb_.IsNull());
240
241 reset_cb_.RunOrHold();
242 }
243
177 } // namespace media 244 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698