| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this |
| 2 // source code is governed by a BSD-style license that can be found in the | 2 // source code is governed by a BSD-style license that can be found in the |
| 3 // LICENSE file. | 3 // 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> |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 // better yet see if we can get away with not using reference counting. | 58 // better yet see if we can get away with not using reference counting. |
| 59 scoped_refptr<Buffer> buffer_ref = buffer; | 59 scoped_refptr<Buffer> buffer_ref = buffer; |
| 60 this->message_loop()->PostTask(FROM_HERE, | 60 this->message_loop()->PostTask(FROM_HERE, |
| 61 NewRunnableMethod(this, &DecoderBase::ReadCompleteTask, buffer_ref)); | 61 NewRunnableMethod(this, &DecoderBase::ReadCompleteTask, buffer_ref)); |
| 62 } | 62 } |
| 63 | 63 |
| 64 protected: | 64 protected: |
| 65 DecoderBase() | 65 DecoderBase() |
| 66 : pending_reads_(0), | 66 : pending_reads_(0), |
| 67 seeking_(false), | 67 seeking_(false), |
| 68 state_(UNINITIALIZED), | 68 state_(UNINITIALIZED) { |
| 69 thread_id_(NULL) { | |
| 70 } | 69 } |
| 71 | 70 |
| 72 virtual ~DecoderBase() { | 71 virtual ~DecoderBase() { |
| 73 DCHECK(state_ == UNINITIALIZED || state_ == STOPPED); | 72 DCHECK(state_ == UNINITIALIZED || state_ == STOPPED); |
| 74 DCHECK(result_queue_.empty()); | 73 DCHECK(result_queue_.empty()); |
| 75 DCHECK(read_queue_.empty()); | 74 DCHECK(read_queue_.empty()); |
| 76 } | 75 } |
| 77 | 76 |
| 78 // 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. |
| 79 // 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 |
| 80 // within the OnDecode method. | 79 // within the OnDecode method. |
| 81 void EnqueueResult(Output* output) { | 80 void EnqueueResult(Output* output) { |
| 82 DCHECK_EQ(PlatformThread::CurrentId(), thread_id_); | 81 DCHECK_EQ(MessageLoop::current(), this->message_loop()); |
| 83 if (!IsStopped()) { | 82 if (!IsStopped()) { |
| 84 result_queue_.push_back(output); | 83 result_queue_.push_back(output); |
| 85 } | 84 } |
| 86 } | 85 } |
| 87 | 86 |
| 88 // Method that must be implemented by the derived class. Called from within | 87 // Method that must be implemented by the derived class. Called from within |
| 89 // the DecoderBase::Initialize() method before any reads are submitted to | 88 // the DecoderBase::Initialize() method before any reads are submitted to |
| 90 // the demuxer stream. Returns true if successful, otherwise false indicates | 89 // the demuxer stream. Returns true if successful, otherwise false indicates |
| 91 // a fatal error. The derived class should NOT call the filter host's | 90 // a fatal error. The derived class should NOT call the filter host's |
| 92 // InitializationComplete() method. If this method returns true, then the | 91 // InitializationComplete() method. If this method returns true, then the |
| 93 // base class will call the host to complete initialization. During this | 92 // base class will call the host to complete initialization. During this |
| 94 // call, the derived class must fill in the media_format_ member. | 93 // call, the derived class must fill in the media_format_ member. |
| 95 virtual bool OnInitialize(DemuxerStream* demuxer_stream) = 0; | 94 virtual bool OnInitialize(DemuxerStream* demuxer_stream) = 0; |
| 96 | 95 |
| 97 // Method that may be implemented by the derived class if desired. It will | 96 // Method that may be implemented by the derived class if desired. It will |
| 98 // be called from within the MediaFilter::Stop() method prior to stopping the | 97 // be called from within the MediaFilter::Stop() method prior to stopping the |
| 99 // base class. | 98 // base class. |
| 100 virtual void OnStop() {} | 99 virtual void OnStop() {} |
| 101 | 100 |
| 102 // Derived class can implement this method and perform seeking logic prior | 101 // Derived class can implement this method and perform seeking logic prior |
| 103 // to the base class. | 102 // to the base class. |
| 104 virtual void OnSeek(base::TimeDelta time) {} | 103 virtual void OnSeek(base::TimeDelta time) {} |
| 105 | 104 |
| 106 // Method that must be implemented by the derived class. If the decode | 105 // Method that must be implemented by the derived class. If the decode |
| 107 // operation produces one or more outputs, the derived class should call | 106 // operation produces one or more outputs, the derived class should call |
| 108 // the EnequeueResult() method from within this method. | 107 // the EnequeueResult() method from within this method. |
| 109 virtual void OnDecode(Buffer* input) = 0; | 108 virtual void OnDecode(Buffer* input) = 0; |
| 110 | 109 |
| 111 // Used for subclasses who friend unit tests and need to set the thread id. | |
| 112 virtual void set_thread_id(PlatformThreadId thread_id) { | |
| 113 thread_id_ = thread_id; | |
| 114 } | |
| 115 | |
| 116 MediaFormat media_format_; | 110 MediaFormat media_format_; |
| 117 | 111 |
| 118 private: | 112 private: |
| 119 bool IsStopped() { return state_ == STOPPED; } | 113 bool IsStopped() { return state_ == STOPPED; } |
| 120 | 114 |
| 121 void StopTask() { | 115 void StopTask() { |
| 122 DCHECK_EQ(PlatformThread::CurrentId(), thread_id_); | 116 DCHECK_EQ(MessageLoop::current(), this->message_loop()); |
| 117 |
| 123 // Delegate to the subclass first. | 118 // Delegate to the subclass first. |
| 124 OnStop(); | 119 OnStop(); |
| 125 | 120 |
| 126 // Throw away all buffers in all queues. | 121 // Throw away all buffers in all queues. |
| 127 result_queue_.clear(); | 122 result_queue_.clear(); |
| 128 STLDeleteElements(&read_queue_); | 123 STLDeleteElements(&read_queue_); |
| 129 state_ = STOPPED; | 124 state_ = STOPPED; |
| 130 } | 125 } |
| 131 | 126 |
| 132 void SeekTask(base::TimeDelta time) { | 127 void SeekTask(base::TimeDelta time) { |
| 133 DCHECK_EQ(PlatformThread::CurrentId(), thread_id_); | 128 DCHECK_EQ(MessageLoop::current(), this->message_loop()); |
| 129 |
| 134 // Delegate to the subclass first. | 130 // Delegate to the subclass first. |
| 135 OnSeek(time); | 131 OnSeek(time); |
| 136 | 132 |
| 137 // Flush the result queue. | 133 // Flush the result queue. |
| 138 result_queue_.clear(); | 134 result_queue_.clear(); |
| 139 | 135 |
| 140 // Turn on the seeking flag so that we can discard buffers until a | 136 // Turn on the seeking flag so that we can discard buffers until a |
| 141 // discontinuous buffer is received. | 137 // discontinuous buffer is received. |
| 142 seeking_ = true; | 138 seeking_ = true; |
| 143 } | 139 } |
| 144 | 140 |
| 145 void InitializeTask(DemuxerStream* demuxer_stream) { | 141 void InitializeTask(DemuxerStream* demuxer_stream) { |
| 142 DCHECK_EQ(MessageLoop::current(), this->message_loop()); |
| 146 DCHECK(state_ == UNINITIALIZED); | 143 DCHECK(state_ == UNINITIALIZED); |
| 147 DCHECK(!demuxer_stream_); | 144 DCHECK(!demuxer_stream_); |
| 148 DCHECK(!thread_id_ || thread_id_ == PlatformThread::CurrentId()); | |
| 149 demuxer_stream_ = demuxer_stream; | 145 demuxer_stream_ = demuxer_stream; |
| 150 | 146 |
| 151 // Grab the thread id for debugging. | |
| 152 thread_id_ = PlatformThread::CurrentId(); | |
| 153 | |
| 154 // Delegate to subclass first. | 147 // Delegate to subclass first. |
| 155 if (!OnInitialize(demuxer_stream_)) { | 148 if (!OnInitialize(demuxer_stream_)) { |
| 156 this->host()->Error(PIPELINE_ERROR_DECODE); | 149 this->host()->Error(PIPELINE_ERROR_DECODE); |
| 157 return; | 150 return; |
| 158 } | 151 } |
| 159 | 152 |
| 160 // TODO(scherkus): subclass shouldn't mutate superclass media format. | 153 // TODO(scherkus): subclass shouldn't mutate superclass media format. |
| 161 DCHECK(!media_format_.empty()) << "Subclass did not set media_format_"; | 154 DCHECK(!media_format_.empty()) << "Subclass did not set media_format_"; |
| 162 state_ = INITIALIZED; | 155 state_ = INITIALIZED; |
| 163 this->host()->InitializationComplete(); | 156 this->host()->InitializationComplete(); |
| 164 } | 157 } |
| 165 | 158 |
| 166 void ReadTask(ReadCallback* read_callback) { | 159 void ReadTask(ReadCallback* read_callback) { |
| 167 DCHECK_EQ(PlatformThread::CurrentId(), thread_id_); | 160 DCHECK_EQ(MessageLoop::current(), this->message_loop()); |
| 161 |
| 168 // TODO(scherkus): should reply with a null operation (empty buffer). | 162 // TODO(scherkus): should reply with a null operation (empty buffer). |
| 169 if (IsStopped()) { | 163 if (IsStopped()) { |
| 170 delete read_callback; | 164 delete read_callback; |
| 171 return; | 165 return; |
| 172 } | 166 } |
| 173 | 167 |
| 174 // Enqueue the callback and attempt to fulfill it immediately. | 168 // Enqueue the callback and attempt to fulfill it immediately. |
| 175 read_queue_.push_back(read_callback); | 169 read_queue_.push_back(read_callback); |
| 176 FulfillPendingRead(); | 170 FulfillPendingRead(); |
| 177 | 171 |
| 178 // Issue reads as necessary. | 172 // Issue reads as necessary. |
| 179 while (pending_reads_ < read_queue_.size()) { | 173 while (pending_reads_ < read_queue_.size()) { |
| 180 demuxer_stream_->Read(NewCallback(this, &DecoderBase::OnReadComplete)); | 174 demuxer_stream_->Read(NewCallback(this, &DecoderBase::OnReadComplete)); |
| 181 ++pending_reads_; | 175 ++pending_reads_; |
| 182 } | 176 } |
| 183 } | 177 } |
| 184 | 178 |
| 185 void ReadCompleteTask(scoped_refptr<Buffer> buffer) { | 179 void ReadCompleteTask(scoped_refptr<Buffer> buffer) { |
| 186 DCHECK_EQ(PlatformThread::CurrentId(), thread_id_); | 180 DCHECK_EQ(MessageLoop::current(), this->message_loop()); |
| 187 DCHECK_GT(pending_reads_, 0u); | 181 DCHECK_GT(pending_reads_, 0u); |
| 188 --pending_reads_; | 182 --pending_reads_; |
| 189 if (IsStopped()) { | 183 if (IsStopped()) { |
| 190 return; | 184 return; |
| 191 } | 185 } |
| 192 | 186 |
| 193 // Once the |seeking_| flag is set we ignore every buffers here | 187 // Once the |seeking_| flag is set we ignore every buffers here |
| 194 // until we receive a discontinuous buffer and we will turn off the | 188 // until we receive a discontinuous buffer and we will turn off the |
| 195 // |seeking_| flag. | 189 // |seeking_| flag. |
| 196 if (buffer->IsDiscontinuous()) { | 190 if (buffer->IsDiscontinuous()) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 219 DCHECK_LE(pending_reads_, read_queue_.size()); | 213 DCHECK_LE(pending_reads_, read_queue_.size()); |
| 220 while (pending_reads_ < read_queue_.size()) { | 214 while (pending_reads_ < read_queue_.size()) { |
| 221 demuxer_stream_->Read(NewCallback(this, &DecoderBase::OnReadComplete)); | 215 demuxer_stream_->Read(NewCallback(this, &DecoderBase::OnReadComplete)); |
| 222 ++pending_reads_; | 216 ++pending_reads_; |
| 223 } | 217 } |
| 224 } | 218 } |
| 225 | 219 |
| 226 // Attempts to fulfill a single pending read by dequeuing a buffer and read | 220 // Attempts to fulfill a single pending read by dequeuing a buffer and read |
| 227 // callback pair and executing the callback. | 221 // callback pair and executing the callback. |
| 228 void FulfillPendingRead() { | 222 void FulfillPendingRead() { |
| 229 DCHECK_EQ(PlatformThread::CurrentId(), thread_id_); | 223 DCHECK_EQ(MessageLoop::current(), this->message_loop()); |
| 230 if (read_queue_.empty() || result_queue_.empty()) { | 224 if (read_queue_.empty() || result_queue_.empty()) { |
| 231 return; | 225 return; |
| 232 } | 226 } |
| 233 | 227 |
| 234 // Dequeue a frame and read callback pair. | 228 // Dequeue a frame and read callback pair. |
| 235 scoped_refptr<Output> output = result_queue_.front(); | 229 scoped_refptr<Output> output = result_queue_.front(); |
| 236 scoped_ptr<ReadCallback> read_callback(read_queue_.front()); | 230 scoped_ptr<ReadCallback> read_callback(read_queue_.front()); |
| 237 result_queue_.pop_front(); | 231 result_queue_.pop_front(); |
| 238 read_queue_.pop_front(); | 232 read_queue_.pop_front(); |
| 239 | 233 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 269 ReadQueue read_queue_; | 263 ReadQueue read_queue_; |
| 270 | 264 |
| 271 // Simple state tracking variable. | 265 // Simple state tracking variable. |
| 272 enum State { | 266 enum State { |
| 273 UNINITIALIZED, | 267 UNINITIALIZED, |
| 274 INITIALIZED, | 268 INITIALIZED, |
| 275 STOPPED, | 269 STOPPED, |
| 276 }; | 270 }; |
| 277 State state_; | 271 State state_; |
| 278 | 272 |
| 279 // Used for debugging. | |
| 280 PlatformThreadId thread_id_; | |
| 281 | |
| 282 DISALLOW_COPY_AND_ASSIGN(DecoderBase); | 273 DISALLOW_COPY_AND_ASSIGN(DecoderBase); |
| 283 }; | 274 }; |
| 284 | 275 |
| 285 } // namespace media | 276 } // namespace media |
| 286 | 277 |
| 287 #endif // MEDIA_FILTERS_DECODER_BASE_H_ | 278 #endif // MEDIA_FILTERS_DECODER_BASE_H_ |
| OLD | NEW |