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

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_);
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() {
158 DCHECK(thread_checker_.CalledOnValidThread());
159 DCHECK(!held_decode_callbacks_.empty());
160
161 RunDecodeCallback(held_decode_callbacks_.front());
162 held_decode_callbacks_.pop_front();
163
164 if (!reset_cb_.IsNull() && held_decode_callbacks_.empty())
149 DoReset(); 165 DoReset();
150 } 166 }
151 167
152 void FakeVideoDecoder::SatisfyReset() { 168 void FakeVideoDecoder::SatisfyReset() {
153 DCHECK(task_runner_->BelongsToCurrentThread()); 169 DCHECK(thread_checker_.CalledOnValidThread());
154 DCHECK(decode_cb_.IsNull()); 170 DCHECK(held_decode_callbacks_.empty());
155 reset_cb_.RunHeldCallback(); 171 reset_cb_.RunHeldCallback();
156 } 172 }
157 173
158 void FakeVideoDecoder::DoReset() { 174 void FakeVideoDecoder::SimulateError() {
159 DCHECK(task_runner_->BelongsToCurrentThread()); 175 DCHECK(thread_checker_.CalledOnValidThread());
160 DCHECK(decode_cb_.IsNull());
161 DCHECK(!reset_cb_.IsNull());
162 176
177 state_ = ERROR;
178 while (!held_decode_callbacks_.empty()) {
179 held_decode_callbacks_.front().Run(kDecodeError,
180 scoped_refptr<VideoFrame>());
181 held_decode_callbacks_.pop_front();
182 }
163 decoded_frames_.clear(); 183 decoded_frames_.clear();
164 reset_cb_.RunOrHold(); 184 }
185
186 int FakeVideoDecoder::GetMaxDecodeRequests() const {
187 return max_parallel_decoding_requests_;
165 } 188 }
166 189
167 void FakeVideoDecoder::OnFrameDecoded( 190 void FakeVideoDecoder::OnFrameDecoded(
168 int buffer_size, 191 int buffer_size,
169 const DecodeCB& decode_cb, 192 const DecodeCB& decode_cb,
170 Status status, 193 Status status,
171 const scoped_refptr<VideoFrame>& video_frame) { 194 const scoped_refptr<VideoFrame>& video_frame) {
195 DCHECK(thread_checker_.CalledOnValidThread());
196
172 if (status == kOk || status == kNotEnoughData) 197 if (status == kOk || status == kNotEnoughData)
173 total_bytes_decoded_ += buffer_size; 198 total_bytes_decoded_ += buffer_size;
174 decode_cb.Run(status, video_frame); 199 decode_cb.Run(status, video_frame);
175 } 200 }
176 201
202 void FakeVideoDecoder::RunOrHoldDecode(const DecodeCB& decode_cb) {
203 DCHECK(thread_checker_.CalledOnValidThread());
204
205 if (hold_decode_) {
206 held_decode_callbacks_.push_back(decode_cb);
207 } else {
208 DCHECK(held_decode_callbacks_.empty());
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()) {
217 DCHECK(decoded_frames_.empty());
218 decode_cb.Run(kAborted, scoped_refptr<VideoFrame>());
219 return;
220 }
221
222 if (decoded_frames_.size() <= decoding_delay_ && state_ != END_OF_STREAM) {
223 decode_cb.Run(kNotEnoughData, scoped_refptr<VideoFrame>());
224 return;
225 }
226
227 scoped_refptr<VideoFrame> frame;
228 if (decoded_frames_.empty()) {
229 DCHECK_EQ(state_, END_OF_STREAM);
230 frame = VideoFrame::CreateEOSFrame();
231 } else {
232 frame = decoded_frames_.front();
233 decoded_frames_.pop_front();
234 }
235 decode_cb.Run(kOk, frame);
236 }
237
238 void FakeVideoDecoder::DoReset() {
239 DCHECK(thread_checker_.CalledOnValidThread());
240 DCHECK(held_decode_callbacks_.empty());
241 DCHECK(!reset_cb_.IsNull());
242
243 reset_cb_.RunOrHold();
244 }
245
177 } // namespace media 246 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698