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

Side by Side Diff: media/filters/decoder_base.h

Issue 6171009: Remove MessageLoop methods from Filter interface (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Applied more CR suggestions & removed message_loop() methods where possible. Created 9 years, 11 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
« no previous file with comments | « media/base/mock_filters.cc ('k') | media/filters/decoder_base_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 // A base class that provides the plumbing for a decoder filters. 5 // A base class that provides the plumbing for a decoder filters.
6 6
7 #ifndef MEDIA_FILTERS_DECODER_BASE_H_ 7 #ifndef MEDIA_FILTERS_DECODER_BASE_H_
8 #define MEDIA_FILTERS_DECODER_BASE_H_ 8 #define MEDIA_FILTERS_DECODER_BASE_H_
9 9
10 #include <deque> 10 #include <deque>
11 11
12 #include "base/callback.h" 12 #include "base/callback.h"
13 #include "base/stl_util-inl.h" 13 #include "base/stl_util-inl.h"
14 #include "base/task.h" 14 #include "base/task.h"
15 #include "base/threading/thread.h" 15 #include "base/threading/thread.h"
16 #include "media/base/buffers.h" 16 #include "media/base/buffers.h"
17 #include "media/base/callback.h" 17 #include "media/base/callback.h"
18 #include "media/base/filters.h" 18 #include "media/base/filters.h"
19 #include "media/base/filter_host.h" 19 #include "media/base/filter_host.h"
20 20
21 namespace media { 21 namespace media {
22 22
23 // In this class, we over-specify method lookup via this-> to avoid unexpected 23 // In this class, we over-specify method lookup via this-> to avoid unexpected
24 // name resolution issues due to the two-phase lookup needed for dependent 24 // name resolution issues due to the two-phase lookup needed for dependent
25 // name resolution in templates. 25 // name resolution in templates.
26 template <class Decoder, class Output> 26 template <class Decoder, class Output>
27 class DecoderBase : public Decoder { 27 class DecoderBase : public Decoder {
28 public: 28 public:
29
30 // Filter implementation. 29 // Filter implementation.
31 virtual void Stop(FilterCallback* callback) { 30 virtual void Stop(FilterCallback* callback) {
32 this->message_loop()->PostTask( 31 message_loop_->PostTask(
33 FROM_HERE, 32 FROM_HERE,
34 NewRunnableMethod(this, &DecoderBase::StopTask, callback)); 33 NewRunnableMethod(this, &DecoderBase::StopTask, callback));
35 } 34 }
36 35
37 virtual void Seek(base::TimeDelta time, 36 virtual void Seek(base::TimeDelta time,
38 FilterCallback* callback) { 37 FilterCallback* callback) {
39 this->message_loop()->PostTask( 38 message_loop_->PostTask(
40 FROM_HERE, 39 FROM_HERE,
41 NewRunnableMethod(this, &DecoderBase::SeekTask, time, callback)); 40 NewRunnableMethod(this, &DecoderBase::SeekTask, time, callback));
42 } 41 }
43 42
44 // Decoder implementation. 43 // Decoder implementation.
45 virtual void Initialize(DemuxerStream* demuxer_stream, 44 virtual void Initialize(DemuxerStream* demuxer_stream,
46 FilterCallback* callback) { 45 FilterCallback* callback) {
47 this->message_loop()->PostTask( 46 message_loop_->PostTask(
48 FROM_HERE, 47 FROM_HERE,
49 NewRunnableMethod(this, 48 NewRunnableMethod(this,
50 &DecoderBase::InitializeTask, 49 &DecoderBase::InitializeTask,
51 make_scoped_refptr(demuxer_stream), 50 make_scoped_refptr(demuxer_stream),
52 callback)); 51 callback));
53 } 52 }
54 53
55 virtual const MediaFormat& media_format() { return media_format_; } 54 virtual const MediaFormat& media_format() { return media_format_; }
56 55
57 // Audio decoder. 56 // Audio decoder.
58 // Note that this class is only used by the audio decoder, this will 57 // Note that this class is only used by the audio decoder, this will
59 // eventually be merged into FFmpegAudioDecoder. 58 // eventually be merged into FFmpegAudioDecoder.
60 virtual void ProduceAudioSamples(scoped_refptr<Output> output) { 59 virtual void ProduceAudioSamples(scoped_refptr<Output> output) {
61 this->message_loop()->PostTask(FROM_HERE, 60 message_loop_->PostTask(FROM_HERE,
62 NewRunnableMethod(this, &DecoderBase::ReadTask, output)); 61 NewRunnableMethod(this, &DecoderBase::ReadTask, output));
63 } 62 }
64 63
65 protected: 64 protected:
66 DecoderBase() 65 explicit DecoderBase(MessageLoop* message_loop)
67 : pending_reads_(0), 66 : message_loop_(message_loop),
67 pending_reads_(0),
68 pending_requests_(0), 68 pending_requests_(0),
69 state_(kUninitialized) { 69 state_(kUninitialized) {
70 } 70 }
71 71
72 virtual ~DecoderBase() { 72 virtual ~DecoderBase() {
73 DCHECK(state_ == kUninitialized || state_ == kStopped); 73 DCHECK(state_ == kUninitialized || state_ == kStopped);
74 DCHECK(result_queue_.empty()); 74 DCHECK(result_queue_.empty());
75 } 75 }
76 76
77 // This method is called by the derived class from within the OnDecode method. 77 // This method is called by the derived class from within the OnDecode method.
78 // It places an output buffer in the result queue. It must be called from 78 // It places an output buffer in the result queue. It must be called from
79 // within the OnDecode method. 79 // within the OnDecode method.
80 void EnqueueResult(Output* output) { 80 void EnqueueResult(Output* output) {
81 DCHECK_EQ(MessageLoop::current(), this->message_loop()); 81 DCHECK_EQ(MessageLoop::current(), message_loop_);
82 if (!IsStopped()) { 82 if (!IsStopped()) {
83 result_queue_.push_back(output); 83 result_queue_.push_back(output);
84 } 84 }
85 } 85 }
86 86
87 // TODO(ajwong): All these "Task*" used as completion callbacks should be 87 // TODO(ajwong): All these "Task*" used as completion callbacks should be
88 // FilterCallbacks. However, since NewCallback() cannot prebind parameters, 88 // FilterCallbacks. However, since NewCallback() cannot prebind parameters,
89 // we use NewRunnableMethod() instead which causes an unfortunate refcount. 89 // we use NewRunnableMethod() instead which causes an unfortunate refcount.
90 // We should move stoyan's Mutant code into base/task.h and turn these 90 // We should move stoyan's Mutant code into base/task.h and turn these
91 // back into FilterCallbacks. 91 // back into FilterCallbacks.
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 // which case |pending_reads_| will remain less than |read_queue_| so we 129 // which case |pending_reads_| will remain less than |read_queue_| so we
130 // need to schedule an additional read. 130 // need to schedule an additional read.
131 DCHECK_LE(pending_reads_, pending_requests_); 131 DCHECK_LE(pending_reads_, pending_requests_);
132 if (!fulfilled) { 132 if (!fulfilled) {
133 DCHECK_LT(pending_reads_, pending_requests_); 133 DCHECK_LT(pending_reads_, pending_requests_);
134 demuxer_stream_->Read(NewCallback(this, &DecoderBase::OnReadComplete)); 134 demuxer_stream_->Read(NewCallback(this, &DecoderBase::OnReadComplete));
135 ++pending_reads_; 135 ++pending_reads_;
136 } 136 }
137 } 137 }
138 138
139 // Provide access to subclasses.
140 MessageLoop* message_loop() { return message_loop_; }
141
139 private: 142 private:
140 bool IsStopped() { return state_ == kStopped; } 143 bool IsStopped() { return state_ == kStopped; }
141 144
142 void OnReadComplete(Buffer* buffer) { 145 void OnReadComplete(Buffer* buffer) {
143 // Little bit of magic here to get NewRunnableMethod() to generate a Task 146 // Little bit of magic here to get NewRunnableMethod() to generate a Task
144 // that holds onto a reference via scoped_refptr<>. 147 // that holds onto a reference via scoped_refptr<>.
145 // 148 //
146 // TODO(scherkus): change the callback format to pass a scoped_refptr<> or 149 // TODO(scherkus): change the callback format to pass a scoped_refptr<> or
147 // better yet see if we can get away with not using reference counting. 150 // better yet see if we can get away with not using reference counting.
148 scoped_refptr<Buffer> buffer_ref = buffer; 151 scoped_refptr<Buffer> buffer_ref = buffer;
149 this->message_loop()->PostTask(FROM_HERE, 152 message_loop_->PostTask(FROM_HERE,
150 NewRunnableMethod(this, &DecoderBase::ReadCompleteTask, buffer_ref)); 153 NewRunnableMethod(this, &DecoderBase::ReadCompleteTask, buffer_ref));
151 } 154 }
152 155
153 void StopTask(FilterCallback* callback) { 156 void StopTask(FilterCallback* callback) {
154 DCHECK_EQ(MessageLoop::current(), this->message_loop()); 157 DCHECK_EQ(MessageLoop::current(), message_loop_);
155 158
156 // Delegate to the subclass first. 159 // Delegate to the subclass first.
157 DoStop(NewRunnableMethod(this, &DecoderBase::OnStopComplete, callback)); 160 DoStop(NewRunnableMethod(this, &DecoderBase::OnStopComplete, callback));
158 } 161 }
159 162
160 void OnStopComplete(FilterCallback* callback) { 163 void OnStopComplete(FilterCallback* callback) {
161 // Throw away all buffers in all queues. 164 // Throw away all buffers in all queues.
162 result_queue_.clear(); 165 result_queue_.clear();
163 state_ = kStopped; 166 state_ = kStopped;
164 167
165 if (callback) { 168 if (callback) {
166 callback->Run(); 169 callback->Run();
167 delete callback; 170 delete callback;
168 } 171 }
169 } 172 }
170 173
171 void SeekTask(base::TimeDelta time, FilterCallback* callback) { 174 void SeekTask(base::TimeDelta time, FilterCallback* callback) {
172 DCHECK_EQ(MessageLoop::current(), this->message_loop()); 175 DCHECK_EQ(MessageLoop::current(), message_loop_);
173 DCHECK_EQ(0u, pending_reads_) << "Pending reads should have completed"; 176 DCHECK_EQ(0u, pending_reads_) << "Pending reads should have completed";
174 DCHECK_EQ(0u, pending_requests_) << "Pending requests should be empty"; 177 DCHECK_EQ(0u, pending_requests_) << "Pending requests should be empty";
175 178
176 // Delegate to the subclass first. 179 // Delegate to the subclass first.
177 DoSeek(time, 180 DoSeek(time,
178 NewRunnableMethod(this, &DecoderBase::OnSeekComplete, callback)); 181 NewRunnableMethod(this, &DecoderBase::OnSeekComplete, callback));
179 } 182 }
180 183
181 void OnSeekComplete(FilterCallback* callback) { 184 void OnSeekComplete(FilterCallback* callback) {
182 // Flush our decoded results. 185 // Flush our decoded results.
183 result_queue_.clear(); 186 result_queue_.clear();
184 187
185 // Signal that we're done seeking. 188 // Signal that we're done seeking.
186 if (callback) { 189 if (callback) {
187 callback->Run(); 190 callback->Run();
188 delete callback; 191 delete callback;
189 } 192 }
190 } 193 }
191 194
192 void InitializeTask(DemuxerStream* demuxer_stream, FilterCallback* callback) { 195 void InitializeTask(DemuxerStream* demuxer_stream, FilterCallback* callback) {
193 DCHECK_EQ(MessageLoop::current(), this->message_loop()); 196 DCHECK_EQ(MessageLoop::current(), message_loop_);
194 CHECK(kUninitialized == state_); 197 CHECK(kUninitialized == state_);
195 CHECK(!demuxer_stream_); 198 CHECK(!demuxer_stream_);
196 demuxer_stream_ = demuxer_stream; 199 demuxer_stream_ = demuxer_stream;
197 200
198 bool* success = new bool; 201 bool* success = new bool;
199 DoInitialize(demuxer_stream, 202 DoInitialize(demuxer_stream,
200 success, 203 success,
201 NewRunnableMethod(this, &DecoderBase::OnInitializeComplete, 204 NewRunnableMethod(this, &DecoderBase::OnInitializeComplete,
202 success, callback)); 205 success, callback));
203 } 206 }
204 207
205 void OnInitializeComplete(bool* success, FilterCallback* done_cb) { 208 void OnInitializeComplete(bool* success, FilterCallback* done_cb) {
206 // Note: The done_runner must be declared *last* to ensure proper 209 // Note: The done_runner must be declared *last* to ensure proper
207 // destruction order. 210 // destruction order.
208 scoped_ptr<bool> success_deleter(success); 211 scoped_ptr<bool> success_deleter(success);
209 AutoCallbackRunner done_runner(done_cb); 212 AutoCallbackRunner done_runner(done_cb);
210 213
211 DCHECK_EQ(MessageLoop::current(), this->message_loop()); 214 DCHECK_EQ(MessageLoop::current(), message_loop_);
212 // Delegate to subclass first. 215 // Delegate to subclass first.
213 if (!*success) { 216 if (!*success) {
214 this->host()->SetError(PIPELINE_ERROR_DECODE); 217 this->host()->SetError(PIPELINE_ERROR_DECODE);
215 } else { 218 } else {
216 // TODO(scherkus): subclass shouldn't mutate superclass media format. 219 // TODO(scherkus): subclass shouldn't mutate superclass media format.
217 DCHECK(!media_format_.empty()) << "Subclass did not set media_format_"; 220 DCHECK(!media_format_.empty()) << "Subclass did not set media_format_";
218 state_ = kInitialized; 221 state_ = kInitialized;
219 } 222 }
220 } 223 }
221 224
222 void ReadTask(scoped_refptr<Output> output) { 225 void ReadTask(scoped_refptr<Output> output) {
223 DCHECK_EQ(MessageLoop::current(), this->message_loop()); 226 DCHECK_EQ(MessageLoop::current(), message_loop_);
224 227
225 // TODO(scherkus): should reply with a null operation (empty buffer). 228 // TODO(scherkus): should reply with a null operation (empty buffer).
226 if (IsStopped()) 229 if (IsStopped())
227 return; 230 return;
228 231
229 ++pending_requests_; 232 ++pending_requests_;
230 233
231 // Try to fulfill it immediately. 234 // Try to fulfill it immediately.
232 if (FulfillPendingRead()) 235 if (FulfillPendingRead())
233 return; 236 return;
234 237
235 // Since we can't fulfill a read request now then submit a read 238 // Since we can't fulfill a read request now then submit a read
236 // request to the demuxer stream. 239 // request to the demuxer stream.
237 demuxer_stream_->Read(NewCallback(this, &DecoderBase::OnReadComplete)); 240 demuxer_stream_->Read(NewCallback(this, &DecoderBase::OnReadComplete));
238 ++pending_reads_; 241 ++pending_reads_;
239 } 242 }
240 243
241 void ReadCompleteTask(scoped_refptr<Buffer> buffer) { 244 void ReadCompleteTask(scoped_refptr<Buffer> buffer) {
242 DCHECK_EQ(MessageLoop::current(), this->message_loop()); 245 DCHECK_EQ(MessageLoop::current(), message_loop_);
243 DCHECK_GT(pending_reads_, 0u); 246 DCHECK_GT(pending_reads_, 0u);
244 --pending_reads_; 247 --pending_reads_;
245 if (IsStopped()) { 248 if (IsStopped()) {
246 return; 249 return;
247 } 250 }
248 251
249 // Decode the frame right away. 252 // Decode the frame right away.
250 DoDecode(buffer); 253 DoDecode(buffer);
251 } 254 }
252 255
253 // Attempts to fulfill a single pending read by dequeuing a buffer and read 256 // Attempts to fulfill a single pending read by dequeuing a buffer and read
254 // callback pair and executing the callback. 257 // callback pair and executing the callback.
255 // 258 //
256 // Return true if one read request is fulfilled. 259 // Return true if one read request is fulfilled.
257 bool FulfillPendingRead() { 260 bool FulfillPendingRead() {
258 DCHECK_EQ(MessageLoop::current(), this->message_loop()); 261 DCHECK_EQ(MessageLoop::current(), message_loop_);
259 if (!pending_requests_ || result_queue_.empty()) { 262 if (!pending_requests_ || result_queue_.empty()) {
260 return false; 263 return false;
261 } 264 }
262 265
263 // Dequeue a frame and read callback pair. 266 // Dequeue a frame and read callback pair.
264 scoped_refptr<Output> output = result_queue_.front(); 267 scoped_refptr<Output> output = result_queue_.front();
265 result_queue_.pop_front(); 268 result_queue_.pop_front();
266 269
267 // Execute the callback! 270 // Execute the callback!
268 --pending_requests_; 271 --pending_requests_;
269 272
270 // TODO(hclam): We only inherit this class from FFmpegAudioDecoder so we 273 // TODO(hclam): We only inherit this class from FFmpegAudioDecoder so we
271 // are making this call. We should correct this by merging this class into 274 // are making this call. We should correct this by merging this class into
272 // FFmpegAudioDecoder. 275 // FFmpegAudioDecoder.
273 Decoder::consume_audio_samples_callback()->Run(output); 276 Decoder::consume_audio_samples_callback()->Run(output);
274 return true; 277 return true;
275 } 278 }
276 279
280 MessageLoop* message_loop_;
281
277 // Tracks the number of asynchronous reads issued to |demuxer_stream_|. 282 // Tracks the number of asynchronous reads issued to |demuxer_stream_|.
278 // Using size_t since it is always compared against deque::size(). 283 // Using size_t since it is always compared against deque::size().
279 size_t pending_reads_; 284 size_t pending_reads_;
280 // Tracks the number of asynchronous reads issued from renderer. 285 // Tracks the number of asynchronous reads issued from renderer.
281 size_t pending_requests_; 286 size_t pending_requests_;
282 287
283 // Pointer to the demuxer stream that will feed us compressed buffers. 288 // Pointer to the demuxer stream that will feed us compressed buffers.
284 scoped_refptr<DemuxerStream> demuxer_stream_; 289 scoped_refptr<DemuxerStream> demuxer_stream_;
285 290
286 // Queue of decoded samples produced in the OnDecode() method of the decoder. 291 // Queue of decoded samples produced in the OnDecode() method of the decoder.
(...skipping 14 matching lines...) Expand all
301 kStopped, 306 kStopped,
302 }; 307 };
303 State state_; 308 State state_;
304 309
305 DISALLOW_COPY_AND_ASSIGN(DecoderBase); 310 DISALLOW_COPY_AND_ASSIGN(DecoderBase);
306 }; 311 };
307 312
308 } // namespace media 313 } // namespace media
309 314
310 #endif // MEDIA_FILTERS_DECODER_BASE_H_ 315 #endif // MEDIA_FILTERS_DECODER_BASE_H_
OLDNEW
« no previous file with comments | « media/base/mock_filters.cc ('k') | media/filters/decoder_base_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698