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

Side by Side Diff: media/base/composite_filter.cc

Issue 10796074: Move VideoRenderer out of Filter heirarchy. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src
Patch Set: Created 8 years, 5 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
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/base/composite_filter.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/callback_helpers.h"
10 #include "base/location.h"
11 #include "base/message_loop_proxy.h"
12 #include "base/stl_util.h"
13
14 namespace media {
15
16 class CompositeFilter::FilterHostImpl : public FilterHost {
17 public:
18 FilterHostImpl(CompositeFilter* parent, FilterHost* host);
19
20 FilterHost* host();
21
22 // media::FilterHost methods.
23 virtual void SetError(PipelineStatus error) OVERRIDE;
24 virtual base::TimeDelta GetTime() const OVERRIDE;
25 virtual base::TimeDelta GetDuration() const OVERRIDE;
26 virtual void SetNaturalVideoSize(const gfx::Size& size) OVERRIDE;
27 virtual void NotifyEnded() OVERRIDE;
28
29 private:
30 CompositeFilter* parent_;
31 FilterHost* host_;
32
33 DISALLOW_COPY_AND_ASSIGN(FilterHostImpl);
34 };
35
36 CompositeFilter::CompositeFilter(
37 const scoped_refptr<base::MessageLoopProxy>& message_loop)
38 : state_(kCreated),
39 sequence_index_(0),
40 message_loop_(message_loop),
41 status_(PIPELINE_OK),
42 weak_ptr_factory_(this) {
43 DCHECK(message_loop);
44 }
45
46 CompositeFilter::~CompositeFilter() {
47 DCHECK(message_loop_->BelongsToCurrentThread());
48 DCHECK(state_ == kCreated || state_ == kStopped);
49
50 filters_.clear();
51 }
52
53 void CompositeFilter::AddFilter(scoped_refptr<Filter> filter) {
54 DCHECK(message_loop_->BelongsToCurrentThread());
55 CHECK(filter && state_ == kCreated && host());
56
57 // Register ourselves as the filter's host.
58 filter->SetHost(host_impl_.get());
59 filters_.push_back(make_scoped_refptr(filter.get()));
60 }
61
62 void CompositeFilter::SetHost(FilterHost* host) {
63 DCHECK(message_loop_->BelongsToCurrentThread());
64 DCHECK(host);
65 DCHECK(!host_impl_.get());
66 host_impl_.reset(new FilterHostImpl(this, host));
67 }
68
69 void CompositeFilter::Play(const base::Closure& play_cb) {
70 DCHECK(message_loop_->BelongsToCurrentThread());
71 if (IsOperationPending()) {
72 SendErrorToHost(PIPELINE_ERROR_OPERATION_PENDING);
73 play_cb.Run();
74 return;
75 } else if (state_ == kPlaying) {
76 play_cb.Run();
77 return;
78 } else if (!host() || (state_ != kPaused && state_ != kCreated)) {
79 SendErrorToHost(PIPELINE_ERROR_INVALID_STATE);
80 play_cb.Run();
81 return;
82 }
83
84 ChangeState(kPlayPending);
85 callback_ = play_cb;
86 StartSerialCallSequence();
87 }
88
89 void CompositeFilter::Pause(const base::Closure& pause_cb) {
90 DCHECK(message_loop_->BelongsToCurrentThread());
91 if (IsOperationPending()) {
92 SendErrorToHost(PIPELINE_ERROR_OPERATION_PENDING);
93 pause_cb.Run();
94 return;
95 } else if (state_ == kPaused) {
96 pause_cb.Run();
97 return;
98 } else if (!host() || state_ != kPlaying) {
99 SendErrorToHost(PIPELINE_ERROR_INVALID_STATE);
100 pause_cb.Run();
101 return;
102 }
103
104 ChangeState(kPausePending);
105 callback_ = pause_cb;
106 StartSerialCallSequence();
107 }
108
109 void CompositeFilter::Flush(const base::Closure& flush_cb) {
110 DCHECK(message_loop_->BelongsToCurrentThread());
111 if (IsOperationPending()) {
112 SendErrorToHost(PIPELINE_ERROR_OPERATION_PENDING);
113 flush_cb.Run();
114 return;
115 } else if (!host() || (state_ != kCreated && state_ != kPaused)) {
116 SendErrorToHost(PIPELINE_ERROR_INVALID_STATE);
117 flush_cb.Run();
118 return;
119 }
120
121 ChangeState(kFlushPending);
122 callback_ = flush_cb;
123 StartParallelCallSequence();
124 }
125
126 void CompositeFilter::Stop(const base::Closure& stop_cb) {
127 DCHECK(message_loop_->BelongsToCurrentThread());
128 if (!host()) {
129 SendErrorToHost(PIPELINE_ERROR_INVALID_STATE);
130 stop_cb.Run();
131 return;
132 } else if (state_ == kStopped) {
133 stop_cb.Run();
134 return;
135 }
136
137 switch (state_) {
138 case kError:
139 case kCreated:
140 case kPaused:
141 case kPlaying:
142 ChangeState(kStopPending);
143 break;
144 case kPlayPending:
145 ChangeState(kStopWhilePlayPending);
146 break;
147 case kPausePending:
148 ChangeState(kStopWhilePausePending);
149 break;
150 case kFlushPending:
151 ChangeState(kStopWhileFlushPending);
152 break;
153 case kSeekPending:
154 ChangeState(kStopWhileSeekPending);
155 break;
156 default:
157 SendErrorToHost(PIPELINE_ERROR_INVALID_STATE);
158 stop_cb.Run();
159 return;
160 }
161
162 if (!status_cb_.is_null()) {
163 DCHECK_EQ(state_, kStopWhileSeekPending);
164 status_cb_.Reset();
165 }
166
167 callback_ = stop_cb;
168 if (state_ == kStopPending) {
169 StartSerialCallSequence();
170 }
171 }
172
173 void CompositeFilter::SetPlaybackRate(float playback_rate) {
174 DCHECK(message_loop_->BelongsToCurrentThread());
175 for (FilterVector::iterator iter = filters_.begin();
176 iter != filters_.end();
177 ++iter) {
178 (*iter)->SetPlaybackRate(playback_rate);
179 }
180 }
181
182 void CompositeFilter::Seek(base::TimeDelta time,
183 const PipelineStatusCB& seek_cb) {
184 DCHECK(message_loop_->BelongsToCurrentThread());
185
186 if (IsOperationPending()) {
187 seek_cb.Run(PIPELINE_ERROR_OPERATION_PENDING);
188 return;
189 } else if (!host() || (state_ != kPaused && state_ != kCreated)) {
190 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE);
191 return;
192 }
193
194 ChangeState(kSeekPending);
195 status_cb_ = seek_cb;
196 pending_seek_time_ = time;
197 StartSerialCallSequence();
198 }
199
200 void CompositeFilter::ChangeState(State new_state) {
201 DCHECK(message_loop_->BelongsToCurrentThread());
202 state_ = new_state;
203 }
204
205 void CompositeFilter::StartSerialCallSequence() {
206 DCHECK(message_loop_->BelongsToCurrentThread());
207 status_ = PIPELINE_OK;
208 sequence_index_ = 0;
209
210 if (!filters_.empty()) {
211 CallFilter(filters_[sequence_index_],
212 NewThreadSafeCallback(&CompositeFilter::SerialCallback));
213 } else {
214 SerialCallback();
215 }
216 }
217
218 void CompositeFilter::StartParallelCallSequence() {
219 DCHECK(message_loop_->BelongsToCurrentThread());
220 status_ = PIPELINE_OK;
221 sequence_index_ = 0;
222
223 if (!filters_.empty()) {
224 for (size_t i = 0; i < filters_.size(); i++) {
225 CallFilter(filters_[i],
226 NewThreadSafeCallback(&CompositeFilter::ParallelCallback));
227 }
228 } else {
229 ParallelCallback();
230 }
231 }
232
233 void CompositeFilter::CallFilter(scoped_refptr<Filter>& filter,
234 const base::Closure& callback) {
235 switch (state_) {
236 case kPlayPending:
237 filter->Play(callback);
238 break;
239 case kPausePending:
240 filter->Pause(callback);
241 break;
242 case kFlushPending:
243 filter->Flush(callback);
244 break;
245 case kStopPending:
246 filter->Stop(callback);
247 break;
248 case kSeekPending:
249 filter->Seek(pending_seek_time_,
250 base::Bind(&CompositeFilter::OnStatusCB, this, callback));
251 break;
252 default:
253 ChangeState(kError);
254 DispatchPendingCallback(PIPELINE_ERROR_INVALID_STATE);
255 }
256 }
257
258 void CompositeFilter::DispatchPendingCallback(PipelineStatus status) {
259 DCHECK(status_cb_.is_null() ^ callback_.is_null());
260
261 if (!status_cb_.is_null()) {
262 base::ResetAndReturn(&status_cb_).Run(status);
263 return;
264 }
265
266 if (!callback_.is_null()) {
267 if (status != PIPELINE_OK)
268 SendErrorToHost(status);
269 base::ResetAndReturn(&callback_).Run();
270 }
271 }
272
273 CompositeFilter::State CompositeFilter::GetNextState(State state) const {
274 State ret = kInvalid;
275 switch (state) {
276 case kPlayPending:
277 ret = kPlaying;
278 break;
279 case kPausePending:
280 case kFlushPending:
281 ret = kPaused;
282 break;
283 case kStopPending:
284 ret = kStopped;
285 break;
286 case kSeekPending:
287 ret = kPaused;
288 break;
289 case kStopWhilePlayPending:
290 case kStopWhilePausePending:
291 case kStopWhileFlushPending:
292 case kStopWhileSeekPending:
293 ret = kStopPending;
294 break;
295
296 case kInvalid:
297 case kCreated:
298 case kPlaying:
299 case kPaused:
300 case kStopped:
301 case kError:
302 ret = kInvalid;
303 break;
304
305 // default: intentionally left out to catch missing states.
306 }
307
308 return ret;
309 }
310
311 void CompositeFilter::SerialCallback() {
312 DCHECK(message_loop_->BelongsToCurrentThread());
313 if (status_ != PIPELINE_OK) {
314 // We encountered an error. Terminate the sequence now.
315 ChangeState(kError);
316 DispatchPendingCallback(status_);
317 return;
318 }
319 if (!filters_.empty())
320 sequence_index_++;
321
322 if (sequence_index_ == filters_.size()) {
323 // All filters have been successfully called without error.
324 OnCallSequenceDone();
325 } else if (GetNextState(state_) == kStopPending) {
326 // Abort sequence early and start issuing Stop() calls.
327 ChangeState(kStopPending);
328 StartSerialCallSequence();
329 } else {
330 // We aren't done with the sequence. Call the next filter.
331 CallFilter(filters_[sequence_index_],
332 NewThreadSafeCallback(&CompositeFilter::SerialCallback));
333 }
334 }
335
336 void CompositeFilter::ParallelCallback() {
337 DCHECK(message_loop_->BelongsToCurrentThread());
338
339 if (!filters_.empty())
340 sequence_index_++;
341
342 if (sequence_index_ == filters_.size()) {
343 if (status_ != PIPELINE_OK) {
344 // We encountered an error.
345 ChangeState(kError);
346 DispatchPendingCallback(status_);
347 return;
348 }
349
350 OnCallSequenceDone();
351 }
352 }
353
354 void CompositeFilter::OnCallSequenceDone() {
355 State next_state = GetNextState(state_);
356 if (next_state == kInvalid) {
357 // We somehow got into an unexpected state.
358 ChangeState(kError);
359 DispatchPendingCallback(PIPELINE_ERROR_INVALID_STATE);
360 return;
361 }
362
363 ChangeState(next_state);
364
365 if (state_ == kStopPending) {
366 // Handle a deferred Stop().
367 StartSerialCallSequence();
368 } else {
369 // Call the callback to indicate that the operation has completed.
370 DispatchPendingCallback(PIPELINE_OK);
371 }
372 }
373
374 void CompositeFilter::SendErrorToHost(PipelineStatus error) {
375 if (host_impl_.get())
376 host_impl_.get()->host()->SetError(error);
377 }
378
379 // Execute |closure| if on |message_loop|, otherwise post to it.
380 static void TrampolineClosureIfNecessary(
381 const scoped_refptr<base::MessageLoopProxy>& message_loop,
382 const base::Closure& closure) {
383 if (message_loop->BelongsToCurrentThread())
384 closure.Run();
385 else
386 message_loop->PostTask(FROM_HERE, closure);
387 }
388
389 base::Closure CompositeFilter::NewThreadSafeCallback(
390 void (CompositeFilter::*method)()) {
391 return base::Bind(&TrampolineClosureIfNecessary,
392 message_loop_,
393 base::Bind(method, weak_ptr_factory_.GetWeakPtr()));
394 }
395
396 bool CompositeFilter::CanForwardError() {
397 return (state_ == kCreated) || (state_ == kPlaying) || (state_ == kPaused);
398 }
399
400 bool CompositeFilter::IsOperationPending() const {
401 DCHECK(callback_.is_null() || status_cb_.is_null());
402
403 return !callback_.is_null() || !status_cb_.is_null();
404 }
405
406 void CompositeFilter::OnStatusCB(const base::Closure& callback,
407 PipelineStatus status) {
408 if (status != PIPELINE_OK)
409 SetError(status);
410
411 callback.Run();
412 }
413
414 FilterHost* CompositeFilter::host() {
415 return host_impl_.get() ? host_impl_.get()->host() : NULL;
416 }
417
418 void CompositeFilter::SetError(PipelineStatus error) {
419 if (!message_loop_->BelongsToCurrentThread()) {
420 message_loop_->PostTask(FROM_HERE,
421 base::Bind(&CompositeFilter::SetError, this, error));
422 return;
423 }
424
425 DCHECK(message_loop_->BelongsToCurrentThread());
426 DCHECK_NE(state_, kCreated);
427
428 // Drop errors recieved while stopping or stopped.
429 // This shields the owner of this object from having
430 // to deal with errors it can't do anything about.
431 if (state_ == kStopPending || state_ == kStopped)
432 return;
433
434 status_ = error;
435 if (CanForwardError())
436 SendErrorToHost(error);
437 }
438
439 CompositeFilter::FilterHostImpl::FilterHostImpl(CompositeFilter* parent,
440 FilterHost* host)
441 : parent_(parent),
442 host_(host) {
443 }
444
445 FilterHost* CompositeFilter::FilterHostImpl::host() {
446 return host_;
447 }
448
449 // media::FilterHost methods.
450 void CompositeFilter::FilterHostImpl::SetError(PipelineStatus error) {
451 parent_->SetError(error);
452 }
453
454 base::TimeDelta CompositeFilter::FilterHostImpl::GetTime() const {
455 return host_->GetTime();
456 }
457
458 base::TimeDelta CompositeFilter::FilterHostImpl::GetDuration() const {
459 return host_->GetDuration();
460 }
461
462 void CompositeFilter::FilterHostImpl::SetNaturalVideoSize(
463 const gfx::Size& size) {
464 host_->SetNaturalVideoSize(size);
465 }
466
467 void CompositeFilter::FilterHostImpl::NotifyEnded() {
468 host_->NotifyEnded();
469 }
470
471 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698