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

Side by Side Diff: media/filters/chunk_demuxer.cc

Issue 7806002: Fix ChunkDemuxer end of stream handling. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix nit and added helper class to reduce duplicated code. Created 9 years, 3 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 | « no previous file | media/filters/chunk_demuxer_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) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 // Implements a Demuxer that can switch among different data sources mid-stream. 5 // Implements a Demuxer that can switch among different data sources mid-stream.
6 // Uses FFmpegDemuxer under the covers, so see the caveats at the top of 6 // Uses FFmpegDemuxer under the covers, so see the caveats at the top of
7 // ffmpeg_demuxer.h. 7 // ffmpeg_demuxer.h.
8 8
9 #include "media/filters/chunk_demuxer.h" 9 #include "media/filters/chunk_demuxer.h"
10 10
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 private: 84 private:
85 static void RunCallback(ReadCallback cb, scoped_refptr<Buffer> buffer); 85 static void RunCallback(ReadCallback cb, scoped_refptr<Buffer> buffer);
86 86
87 Type type_; 87 Type type_;
88 AVStream* av_stream_; 88 AVStream* av_stream_;
89 89
90 mutable base::Lock lock_; 90 mutable base::Lock lock_;
91 ReadCBQueue read_cbs_; 91 ReadCBQueue read_cbs_;
92 BufferQueue buffers_; 92 BufferQueue buffers_;
93 bool shutdown_called_; 93 bool shutdown_called_;
94 bool received_end_of_stream_;
94 95
95 // Keeps track of the timestamp of the last buffer we have 96 // Keeps track of the timestamp of the last buffer we have
96 // added to |buffers_|. This is used to enforce buffers with strictly 97 // added to |buffers_|. This is used to enforce buffers with strictly
97 // monotonically increasing timestamps. 98 // monotonically increasing timestamps.
98 base::TimeDelta last_buffer_timestamp_; 99 base::TimeDelta last_buffer_timestamp_;
99 100
100 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); 101 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream);
101 }; 102 };
102 103
103 ChunkDemuxerStream::ChunkDemuxerStream(Type type, AVStream* stream) 104 ChunkDemuxerStream::ChunkDemuxerStream(Type type, AVStream* stream)
104 : type_(type), 105 : type_(type),
105 av_stream_(stream), 106 av_stream_(stream),
106 shutdown_called_(false), 107 shutdown_called_(false),
108 received_end_of_stream_(false),
107 last_buffer_timestamp_(kNoTimestamp) { 109 last_buffer_timestamp_(kNoTimestamp) {
108 } 110 }
109 111
110 ChunkDemuxerStream::~ChunkDemuxerStream() {} 112 ChunkDemuxerStream::~ChunkDemuxerStream() {}
111 113
112 void ChunkDemuxerStream::Flush() { 114 void ChunkDemuxerStream::Flush() {
113 VLOG(1) << "Flush()"; 115 VLOG(1) << "Flush()";
114 base::AutoLock auto_lock(lock_); 116 base::AutoLock auto_lock(lock_);
115 buffers_.clear(); 117 buffers_.clear();
118 received_end_of_stream_ = false;
116 last_buffer_timestamp_ = kNoTimestamp; 119 last_buffer_timestamp_ = kNoTimestamp;
117 } 120 }
118 121
119 bool ChunkDemuxerStream::CanAddBuffers(const BufferQueue& buffers) const { 122 bool ChunkDemuxerStream::CanAddBuffers(const BufferQueue& buffers) const {
120 base::AutoLock auto_lock(lock_); 123 base::AutoLock auto_lock(lock_);
121 124
122 // If we haven't seen any buffers yet than anything can be added. 125 // If we haven't seen any buffers yet than anything can be added.
123 if (last_buffer_timestamp_ == kNoTimestamp) 126 if (last_buffer_timestamp_ == kNoTimestamp)
124 return true; 127 return true;
125 128
126 if (buffers.empty()) 129 if (buffers.empty())
127 return true; 130 return true;
128 131
129 return (buffers.front()->GetTimestamp() > last_buffer_timestamp_); 132 return (buffers.front()->GetTimestamp() > last_buffer_timestamp_);
130 } 133 }
131 134
132 void ChunkDemuxerStream::AddBuffers(const BufferQueue& buffers) { 135 void ChunkDemuxerStream::AddBuffers(const BufferQueue& buffers) {
133 if (buffers.empty()) 136 if (buffers.empty())
134 return; 137 return;
135 138
136 std::deque<base::Closure> callbacks; 139 std::deque<base::Closure> callbacks;
137 { 140 {
138 base::AutoLock auto_lock(lock_); 141 base::AutoLock auto_lock(lock_);
139 142
140 for (BufferQueue::const_iterator itr = buffers.begin(); 143 for (BufferQueue::const_iterator itr = buffers.begin();
141 itr != buffers.end(); itr++) { 144 itr != buffers.end(); itr++) {
145 // Make sure we aren't trying to add a buffer after we have received and
146 // "end of stream" buffer.
147 DCHECK(!received_end_of_stream_);
142 148
143 if (!(*itr)->IsEndOfStream()) { 149 if ((*itr)->IsEndOfStream()) {
150 received_end_of_stream_ = true;
151
152 // Push enough EOS buffers to satisfy outstanding Read() requests.
153 if (read_cbs_.size() > buffers_.size()) {
154 size_t pending_read_without_data = read_cbs_.size() - buffers_.size();
155 for (size_t i = 0; i <= pending_read_without_data; ++i) {
156 buffers_.push_back(*itr);
157 }
158 }
159 } else {
144 base::TimeDelta current_ts = (*itr)->GetTimestamp(); 160 base::TimeDelta current_ts = (*itr)->GetTimestamp();
145 if (last_buffer_timestamp_ != kNoTimestamp) { 161 if (last_buffer_timestamp_ != kNoTimestamp) {
146 DCHECK_GT(current_ts.ToInternalValue(), 162 DCHECK_GT(current_ts.ToInternalValue(),
147 last_buffer_timestamp_.ToInternalValue()); 163 last_buffer_timestamp_.ToInternalValue());
148 } 164 }
149 165
150 last_buffer_timestamp_ = current_ts; 166 last_buffer_timestamp_ = current_ts;
167 buffers_.push_back(*itr);
151 } 168 }
152
153 buffers_.push_back(*itr);
154 } 169 }
155 170
156 while (!buffers_.empty() && !read_cbs_.empty()) { 171 while (!buffers_.empty() && !read_cbs_.empty()) {
157 callbacks.push_back(base::Bind(&ChunkDemuxerStream::RunCallback, 172 callbacks.push_back(base::Bind(&ChunkDemuxerStream::RunCallback,
158 read_cbs_.front(), 173 read_cbs_.front(),
159 buffers_.front())); 174 buffers_.front()));
160 buffers_.pop_front(); 175 buffers_.pop_front();
161 read_cbs_.pop_front(); 176 read_cbs_.pop_front();
162 } 177 }
163 } 178 }
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 read_callback.Run(buffer); 238 read_callback.Run(buffer);
224 } 239 }
225 240
226 // DemuxerStream methods. 241 // DemuxerStream methods.
227 void ChunkDemuxerStream::Read(const ReadCallback& read_callback) { 242 void ChunkDemuxerStream::Read(const ReadCallback& read_callback) {
228 scoped_refptr<Buffer> buffer; 243 scoped_refptr<Buffer> buffer;
229 244
230 { 245 {
231 base::AutoLock auto_lock(lock_); 246 base::AutoLock auto_lock(lock_);
232 247
233 if (shutdown_called_) { 248 if (shutdown_called_ || (received_end_of_stream_ && buffers_.empty())) {
234 buffer = CreateEOSBuffer(); 249 buffer = CreateEOSBuffer();
235 } else { 250 } else {
236 if (buffers_.empty()) { 251 if (buffers_.empty()) {
237 // Wrap & store |read_callback| so that it will 252 // Wrap & store |read_callback| so that it will
238 // get called on the current MessageLoop. 253 // get called on the current MessageLoop.
239 read_cbs_.push_back(base::Bind(&RunOnMessageLoop, 254 read_cbs_.push_back(base::Bind(&RunOnMessageLoop,
240 read_callback, 255 read_callback,
241 MessageLoop::current())); 256 MessageLoop::current()));
242 return; 257 return;
243 } 258 }
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after
700 base::AutoUnlock auto_unlock(lock_); 715 base::AutoUnlock auto_unlock(lock_);
701 if (cb.is_null()) { 716 if (cb.is_null()) {
702 host()->SetError(error); 717 host()->SetError(error);
703 return; 718 return;
704 } 719 }
705 cb.Run(error); 720 cb.Run(error);
706 } 721 }
707 } 722 }
708 723
709 } // namespace media 724 } // namespace media
OLDNEW
« no previous file with comments | « no previous file | media/filters/chunk_demuxer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698