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

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

Issue 11420070: Remove locking from FFmpegDemuxerStream and associated TODOs from media code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 1 month 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 (c) 2012 The Chromium Authors. All rights reserved. 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 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/ffmpeg_demuxer.h" 5 #include "media/filters/ffmpeg_demuxer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 17 matching lines...) Expand all
28 28
29 namespace media { 29 namespace media {
30 30
31 // 31 //
32 // FFmpegDemuxerStream 32 // FFmpegDemuxerStream
33 // 33 //
34 FFmpegDemuxerStream::FFmpegDemuxerStream( 34 FFmpegDemuxerStream::FFmpegDemuxerStream(
35 FFmpegDemuxer* demuxer, 35 FFmpegDemuxer* demuxer,
36 AVStream* stream) 36 AVStream* stream)
37 : demuxer_(demuxer), 37 : demuxer_(demuxer),
38 message_loop_(base::MessageLoopProxy::current()),
38 stream_(stream), 39 stream_(stream),
39 type_(UNKNOWN), 40 type_(UNKNOWN),
40 stopped_(false), 41 stopped_(false),
41 last_packet_timestamp_(kNoTimestamp()), 42 last_packet_timestamp_(kNoTimestamp()),
42 bitstream_converter_enabled_(false) { 43 bitstream_converter_enabled_(false) {
43 DCHECK(demuxer_); 44 DCHECK(demuxer_);
44 45
45 // Determine our media format. 46 // Determine our media format.
46 switch (stream->codec->codec_type) { 47 switch (stream->codec->codec_type) {
47 case AVMEDIA_TYPE_AUDIO: 48 case AVMEDIA_TYPE_AUDIO:
(...skipping 12 matching lines...) Expand all
60 // Calculate the duration. 61 // Calculate the duration.
61 duration_ = ConvertStreamTimestamp(stream->time_base, stream->duration); 62 duration_ = ConvertStreamTimestamp(stream->time_base, stream->duration);
62 63
63 if (stream_->codec->codec_id == CODEC_ID_H264) { 64 if (stream_->codec->codec_id == CODEC_ID_H264) {
64 bitstream_converter_.reset( 65 bitstream_converter_.reset(
65 new FFmpegH264ToAnnexBBitstreamConverter(stream_->codec)); 66 new FFmpegH264ToAnnexBBitstreamConverter(stream_->codec));
66 } 67 }
67 } 68 }
68 69
69 bool FFmpegDemuxerStream::HasPendingReads() { 70 bool FFmpegDemuxerStream::HasPendingReads() {
70 DCHECK(demuxer_->message_loop()->BelongsToCurrentThread()); 71 DCHECK(message_loop_->BelongsToCurrentThread());
71 base::AutoLock auto_lock(lock_);
72 DCHECK(!stopped_ || read_queue_.empty()) 72 DCHECK(!stopped_ || read_queue_.empty())
73 << "Read queue should have been emptied if demuxing stream is stopped"; 73 << "Read queue should have been emptied if demuxing stream is stopped";
74 return !read_queue_.empty(); 74 return !read_queue_.empty();
75 } 75 }
76 76
77 void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) { 77 void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) {
78 DCHECK(demuxer_->message_loop()->BelongsToCurrentThread()); 78 DCHECK(message_loop_->BelongsToCurrentThread());
79 79
80 base::AutoLock auto_lock(lock_);
81 if (stopped_) { 80 if (stopped_) {
82 NOTREACHED() << "Attempted to enqueue packet on a stopped stream"; 81 NOTREACHED() << "Attempted to enqueue packet on a stopped stream";
83 return; 82 return;
84 } 83 }
85 84
86 scoped_refptr<DecoderBuffer> buffer; 85 scoped_refptr<DecoderBuffer> buffer;
87 if (!packet.get()) { 86 if (!packet.get()) {
88 buffer = DecoderBuffer::CreateEOSBuffer(); 87 buffer = DecoderBuffer::CreateEOSBuffer();
89 } else { 88 } else {
90 // Convert the packet if there is a bitstream filter. 89 // Convert the packet if there is a bitstream filter.
91 if (packet->data && bitstream_converter_enabled_ && 90 if (packet->data && bitstream_converter_enabled_ &&
92 !bitstream_converter_->ConvertPacket(packet.get())) { 91 !bitstream_converter_->ConvertPacket(packet.get())) {
93 LOG(ERROR) << "Format converstion failed."; 92 LOG(ERROR) << "Format converstion failed.";
94 } 93 }
95 94
96 // If a packet is returned by FFmpeg's av_parser_parse2() the packet will 95 // If a packet is returned by FFmpeg's av_parser_parse2() the packet will
97 // reference inner memory of FFmpeg. As such we should transfer the packet 96 // reference inner memory of FFmpeg. As such we should transfer the packet
98 // into memory we control. 97 // into memory we control.
99 buffer = DecoderBuffer::CopyFrom(packet->data, packet->size); 98 buffer = DecoderBuffer::CopyFrom(packet->data, packet->size);
100 buffer->SetTimestamp(ConvertStreamTimestamp( 99 buffer->SetTimestamp(ConvertStreamTimestamp(
101 stream_->time_base, packet->pts)); 100 stream_->time_base, packet->pts));
102 buffer->SetDuration(ConvertStreamTimestamp( 101 buffer->SetDuration(ConvertStreamTimestamp(
103 stream_->time_base, packet->duration)); 102 stream_->time_base, packet->duration));
104 if (buffer->GetTimestamp() != kNoTimestamp() && 103 if (buffer->GetTimestamp() != kNoTimestamp() &&
105 last_packet_timestamp_ != kNoTimestamp() && 104 last_packet_timestamp_ != kNoTimestamp() &&
106 last_packet_timestamp_ < buffer->GetTimestamp()) { 105 last_packet_timestamp_ < buffer->GetTimestamp()) {
107 buffered_ranges_.Add(last_packet_timestamp_, buffer->GetTimestamp()); 106 buffered_ranges_.Add(last_packet_timestamp_, buffer->GetTimestamp());
108 demuxer_->message_loop()->PostTask(FROM_HERE, base::Bind( 107 demuxer_->NotifyBufferingChanged();
109 &FFmpegDemuxer::NotifyBufferingChanged, demuxer_));
110 } 108 }
111 last_packet_timestamp_ = buffer->GetTimestamp(); 109 last_packet_timestamp_ = buffer->GetTimestamp();
112 } 110 }
113 111
114 buffer_queue_.push_back(buffer); 112 buffer_queue_.push_back(buffer);
115 FulfillPendingRead(); 113 SatisfyPendingReads();
116 return;
117 } 114 }
118 115
119 void FFmpegDemuxerStream::FlushBuffers() { 116 void FFmpegDemuxerStream::FlushBuffers() {
120 DCHECK(demuxer_->message_loop()->BelongsToCurrentThread()); 117 DCHECK(message_loop_->BelongsToCurrentThread());
121 base::AutoLock auto_lock(lock_);
122 DCHECK(read_queue_.empty()) << "Read requests should be empty"; 118 DCHECK(read_queue_.empty()) << "Read requests should be empty";
123 buffer_queue_.clear(); 119 buffer_queue_.clear();
124 last_packet_timestamp_ = kNoTimestamp(); 120 last_packet_timestamp_ = kNoTimestamp();
125 } 121 }
126 122
127 void FFmpegDemuxerStream::Stop() { 123 void FFmpegDemuxerStream::Stop() {
128 DCHECK(demuxer_->message_loop()->BelongsToCurrentThread()); 124 DCHECK(message_loop_->BelongsToCurrentThread());
129 base::AutoLock auto_lock(lock_);
130 buffer_queue_.clear(); 125 buffer_queue_.clear();
131 for (ReadQueue::iterator it = read_queue_.begin(); 126 for (ReadQueue::iterator it = read_queue_.begin();
132 it != read_queue_.end(); ++it) { 127 it != read_queue_.end(); ++it) {
133 it->Run(DemuxerStream::kOk, 128 it->Run(DemuxerStream::kOk,
134 scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer())); 129 scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer()));
xhwang 2012/11/20 17:54:34 CreateEOSBuffer() returns scoped_refptr<DecoderBuf
scherkus (not reviewing) 2012/11/20 19:16:07 Done.
135 } 130 }
136 read_queue_.clear(); 131 read_queue_.clear();
137 stopped_ = true; 132 stopped_ = true;
138 } 133 }
139 134
140 base::TimeDelta FFmpegDemuxerStream::duration() { 135 base::TimeDelta FFmpegDemuxerStream::duration() {
141 return duration_; 136 return duration_;
142 } 137 }
143 138
144 DemuxerStream::Type FFmpegDemuxerStream::type() { 139 DemuxerStream::Type FFmpegDemuxerStream::type() {
145 return type_; 140 return type_;
146 } 141 }
147 142
148 void FFmpegDemuxerStream::Read(const ReadCB& read_cb) { 143 void FFmpegDemuxerStream::Read(const ReadCB& read_cb) {
149 DCHECK(!read_cb.is_null()); 144 if (!message_loop_->BelongsToCurrentThread()) {
145 message_loop_->PostTask(FROM_HERE, base::Bind(
146 &FFmpegDemuxerStream::Read, this, read_cb));
147 return;
148 }
150 149
151 base::AutoLock auto_lock(lock_);
152 // Don't accept any additional reads if we've been told to stop. 150 // Don't accept any additional reads if we've been told to stop.
153 // The demuxer_ may have been destroyed in the pipleine thread. 151 // The |demuxer_| may have been destroyed in the pipeline thread.
154 // 152 //
155 // TODO(scherkus): it would be cleaner if we replied with an error message. 153 // TODO(scherkus): it would be cleaner to reply with an error message.
156 if (stopped_) { 154 if (stopped_) {
157 read_cb.Run(DemuxerStream::kOk, 155 read_cb.Run(DemuxerStream::kOk,
158 scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer())); 156 scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer()));
xhwang 2012/11/20 17:54:34 ditto
scherkus (not reviewing) 2012/11/20 19:16:07 Done.
159 return; 157 return;
160 } 158 }
161 159
162 // Buffers are only queued when there are no pending reads.
163 DCHECK(buffer_queue_.empty() || read_queue_.empty());
164
165 if (buffer_queue_.empty()) {
166 demuxer_->message_loop()->PostTask(FROM_HERE, base::Bind(
167 &FFmpegDemuxerStream::ReadTask, this, read_cb));
168 return;
169 }
170
171 // Send the oldest buffer back.
172 scoped_refptr<DecoderBuffer> buffer = buffer_queue_.front();
173 buffer_queue_.pop_front();
174 read_cb.Run(DemuxerStream::kOk, buffer);
175 }
176
177 void FFmpegDemuxerStream::ReadTask(const ReadCB& read_cb) {
178 DCHECK(demuxer_->message_loop()->BelongsToCurrentThread());
179
180 base::AutoLock auto_lock(lock_);
181 // Don't accept any additional reads if we've been told to stop.
182 //
183 // TODO(scherkus): it would be cleaner if we replied with an error message.
184 if (stopped_) {
185 read_cb.Run(DemuxerStream::kOk,
186 scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer()));
187 return;
188 }
189
190 // Enqueue the callback and attempt to satisfy it immediately.
191 read_queue_.push_back(read_cb); 160 read_queue_.push_back(read_cb);
192 FulfillPendingRead(); 161 SatisfyPendingReads();
193
194 // Check if there are still pending reads, demux some more.
195 if (!read_queue_.empty()) {
196 demuxer_->PostDemuxTask();
197 }
198 }
199
200 void FFmpegDemuxerStream::FulfillPendingRead() {
201 DCHECK(demuxer_->message_loop()->BelongsToCurrentThread());
202 lock_.AssertAcquired();
203 if (buffer_queue_.empty() || read_queue_.empty()) {
204 return;
205 }
206
207 // Dequeue a buffer and pending read pair.
208 scoped_refptr<DecoderBuffer> buffer = buffer_queue_.front();
209 ReadCB read_cb(read_queue_.front());
210 buffer_queue_.pop_front();
211 read_queue_.pop_front();
212
213 // Execute the callback.
214 read_cb.Run(DemuxerStream::kOk, buffer);
215 } 162 }
216 163
217 void FFmpegDemuxerStream::EnableBitstreamConverter() { 164 void FFmpegDemuxerStream::EnableBitstreamConverter() {
218 base::AutoLock auto_lock(lock_); 165 if (!message_loop_->BelongsToCurrentThread()) {
166 message_loop_->PostTask(FROM_HERE, base::Bind(
167 &FFmpegDemuxerStream::EnableBitstreamConverter, this));
168 return;
169 }
219 CHECK(bitstream_converter_.get()); 170 CHECK(bitstream_converter_.get());
220 bitstream_converter_enabled_ = true; 171 bitstream_converter_enabled_ = true;
221 } 172 }
222 173
223 const AudioDecoderConfig& FFmpegDemuxerStream::audio_decoder_config() { 174 const AudioDecoderConfig& FFmpegDemuxerStream::audio_decoder_config() {
224 CHECK_EQ(type_, AUDIO); 175 CHECK_EQ(type_, AUDIO);
225 return audio_config_; 176 return audio_config_;
226 } 177 }
227 178
228 const VideoDecoderConfig& FFmpegDemuxerStream::video_decoder_config() { 179 const VideoDecoderConfig& FFmpegDemuxerStream::video_decoder_config() {
229 CHECK_EQ(type_, VIDEO); 180 CHECK_EQ(type_, VIDEO);
230 return video_config_; 181 return video_config_;
231 } 182 }
232 183
233 FFmpegDemuxerStream::~FFmpegDemuxerStream() { 184 FFmpegDemuxerStream::~FFmpegDemuxerStream() {
234 base::AutoLock auto_lock(lock_);
235 DCHECK(stopped_); 185 DCHECK(stopped_);
236 DCHECK(read_queue_.empty()); 186 DCHECK(read_queue_.empty());
237 DCHECK(buffer_queue_.empty()); 187 DCHECK(buffer_queue_.empty());
238 } 188 }
239 189
240 base::TimeDelta FFmpegDemuxerStream::GetElapsedTime() const { 190 base::TimeDelta FFmpegDemuxerStream::GetElapsedTime() const {
241 return ConvertStreamTimestamp(stream_->time_base, stream_->cur_dts); 191 return ConvertStreamTimestamp(stream_->time_base, stream_->cur_dts);
242 } 192 }
243 193
244 Ranges<base::TimeDelta> FFmpegDemuxerStream::GetBufferedRanges() const { 194 Ranges<base::TimeDelta> FFmpegDemuxerStream::GetBufferedRanges() const {
245 base::AutoLock auto_lock(lock_);
246 return buffered_ranges_; 195 return buffered_ranges_;
247 } 196 }
248 197
198 void FFmpegDemuxerStream::SatisfyPendingReads() {
xhwang 2012/11/20 17:54:34 Add DCHECK(message_loop_->BelongsToCurrentThread()
scherkus (not reviewing) 2012/11/20 19:16:07 Done.
199 while (!read_queue_.empty() && !buffer_queue_.empty()) {
200 ReadCB read_cb = read_queue_.front();
201 read_queue_.pop_front();
202
203 // Send earliest buffer back on a new execution stack to avoid recursing.
204 scoped_refptr<DecoderBuffer> buffer = buffer_queue_.front();
205 buffer_queue_.pop_front();
206 message_loop_->PostTask(FROM_HERE, base::Bind(
207 read_cb, DemuxerStream::kOk, buffer));
208 }
209
210 // No buffers but pending reads? Ask for more!
211 if (!read_queue_.empty() && buffer_queue_.empty()) {
212 demuxer_->NotifyHasPendingRead();
213 }
214 }
215
249 // static 216 // static
250 base::TimeDelta FFmpegDemuxerStream::ConvertStreamTimestamp( 217 base::TimeDelta FFmpegDemuxerStream::ConvertStreamTimestamp(
251 const AVRational& time_base, int64 timestamp) { 218 const AVRational& time_base, int64 timestamp) {
252 if (timestamp == static_cast<int64>(AV_NOPTS_VALUE)) 219 if (timestamp == static_cast<int64>(AV_NOPTS_VALUE))
253 return kNoTimestamp(); 220 return kNoTimestamp();
254 221
255 return ConvertFromTimeBase(time_base, timestamp); 222 return ConvertFromTimeBase(time_base, timestamp);
256 } 223 }
257 224
258 // 225 //
(...skipping 11 matching lines...) Expand all
270 audio_disabled_(false), 237 audio_disabled_(false),
271 duration_known_(false), 238 duration_known_(false),
272 url_protocol_(data_source, BindToLoop(message_loop_, base::Bind( 239 url_protocol_(data_source, BindToLoop(message_loop_, base::Bind(
273 &FFmpegDemuxer::OnDataSourceError, base::Unretained(this)))) { 240 &FFmpegDemuxer::OnDataSourceError, base::Unretained(this)))) {
274 DCHECK(message_loop_); 241 DCHECK(message_loop_);
275 DCHECK(data_source_); 242 DCHECK(data_source_);
276 } 243 }
277 244
278 FFmpegDemuxer::~FFmpegDemuxer() {} 245 FFmpegDemuxer::~FFmpegDemuxer() {}
279 246
280 void FFmpegDemuxer::PostDemuxTask() {
281 message_loop_->PostTask(FROM_HERE,
282 base::Bind(&FFmpegDemuxer::DemuxTask, this));
283 }
284
285 void FFmpegDemuxer::Stop(const base::Closure& callback) { 247 void FFmpegDemuxer::Stop(const base::Closure& callback) {
286 // Post a task to notify the streams to stop as well. 248 // Post a task to notify the streams to stop as well.
287 message_loop_->PostTask(FROM_HERE, 249 message_loop_->PostTask(FROM_HERE,
288 base::Bind(&FFmpegDemuxer::StopTask, this, callback)); 250 base::Bind(&FFmpegDemuxer::StopTask, this, callback));
289 } 251 }
290 252
291 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { 253 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
292 message_loop_->PostTask(FROM_HERE, 254 message_loop_->PostTask(FROM_HERE,
293 base::Bind(&FFmpegDemuxer::SeekTask, this, time, cb)); 255 base::Bind(&FFmpegDemuxer::SeekTask, this, time, cb));
294 } 256 }
(...skipping 27 matching lines...) Expand all
322 return *iter; 284 return *iter;
323 } 285 }
324 } 286 }
325 return NULL; 287 return NULL;
326 } 288 }
327 289
328 base::TimeDelta FFmpegDemuxer::GetStartTime() const { 290 base::TimeDelta FFmpegDemuxer::GetStartTime() const {
329 return start_time_; 291 return start_time_;
330 } 292 }
331 293
332 scoped_refptr<base::MessageLoopProxy> FFmpegDemuxer::message_loop() {
333 return message_loop_;
334 }
335
336 // Helper for calculating the bitrate of the media based on information stored 294 // Helper for calculating the bitrate of the media based on information stored
337 // in |format_context| or failing that the size and duration of the media. 295 // in |format_context| or failing that the size and duration of the media.
338 // 296 //
339 // Returns 0 if a bitrate could not be determined. 297 // Returns 0 if a bitrate could not be determined.
340 static int CalculateBitrate( 298 static int CalculateBitrate(
341 AVFormatContext* format_context, 299 AVFormatContext* format_context,
342 const base::TimeDelta& duration, 300 const base::TimeDelta& duration,
343 int64 filesize_in_bytes) { 301 int64 filesize_in_bytes) {
344 // If there is a bitrate set on the container, use it. 302 // If there is a bitrate set on the container, use it.
345 if (format_context->bit_rate > 0) 303 if (format_context->bit_rate > 0)
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after
593 } 551 }
594 } 552 }
595 } 553 }
596 // If we have reached the end of stream, tell the downstream filters about 554 // If we have reached the end of stream, tell the downstream filters about
597 // the event. 555 // the event.
598 StreamHasEnded(); 556 StreamHasEnded();
599 return; 557 return;
600 } 558 }
601 559
602 // Queue the packet with the appropriate stream. 560 // Queue the packet with the appropriate stream.
603 // TODO(scherkus): should we post this back to the pipeline thread? I'm
604 // worried about downstream filters (i.e., decoders) executing on this
605 // thread.
606 DCHECK_GE(packet->stream_index, 0); 561 DCHECK_GE(packet->stream_index, 0);
607 DCHECK_LT(packet->stream_index, static_cast<int>(streams_.size())); 562 DCHECK_LT(packet->stream_index, static_cast<int>(streams_.size()));
608 563
609 // Defend against ffmpeg giving us a bad stream index. 564 // Defend against ffmpeg giving us a bad stream index.
610 if (packet->stream_index >= 0 && 565 if (packet->stream_index >= 0 &&
611 packet->stream_index < static_cast<int>(streams_.size()) && 566 packet->stream_index < static_cast<int>(streams_.size()) &&
612 streams_[packet->stream_index] && 567 streams_[packet->stream_index] &&
613 (!audio_disabled_ || 568 (!audio_disabled_ ||
614 streams_[packet->stream_index]->type() != DemuxerStream::AUDIO)) { 569 streams_[packet->stream_index]->type() != DemuxerStream::AUDIO)) {
615 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index]; 570 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index];
616 demuxer_stream->EnqueuePacket(packet.Pass()); 571 demuxer_stream->EnqueuePacket(packet.Pass());
617 } 572 }
618 573
619 // Create a loop by posting another task. This allows seek and message loop 574 // Create a loop by posting another task. This allows seek and message loop
620 // quit tasks to get processed. 575 // quit tasks to get processed.
621 if (StreamsHavePendingReads()) { 576 if (StreamsHavePendingReads()) {
622 PostDemuxTask(); 577 message_loop_->PostTask(FROM_HERE, base::Bind(
578 &FFmpegDemuxer::DemuxTask, this));
623 } 579 }
624 } 580 }
625 581
626 void FFmpegDemuxer::StopTask(const base::Closure& callback) { 582 void FFmpegDemuxer::StopTask(const base::Closure& callback) {
627 DCHECK(message_loop_->BelongsToCurrentThread()); 583 DCHECK(message_loop_->BelongsToCurrentThread());
628 StreamVector::iterator iter;
629 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
630 if (*iter)
631 (*iter)->Stop();
632 }
633
634 url_protocol_.Abort(); 584 url_protocol_.Abort();
635 data_source_->Stop(BindToLoop(message_loop_, base::Bind( 585 data_source_->Stop(BindToLoop(message_loop_, base::Bind(
636 &FFmpegDemuxer::OnDataSourceStopped, this, callback))); 586 &FFmpegDemuxer::OnDataSourceStopped, this, callback)));
637 } 587 }
638 588
639 void FFmpegDemuxer::OnDataSourceStopped(const base::Closure& callback) { 589 void FFmpegDemuxer::OnDataSourceStopped(const base::Closure& callback) {
640 // This will block until all tasks complete. Note that after this returns it's 590 // This will block until all tasks complete. Note that after this returns it's
641 // possible for reply tasks (e.g., OnReadFrameDone()) to be queued on this 591 // possible for reply tasks (e.g., OnReadFrameDone()) to be queued on this
642 // thread. Each of the reply task methods must check whether we've stopped the 592 // thread. Each of the reply task methods must check whether we've stopped the
643 // thread and drop their results on the floor. 593 // thread and drop their results on the floor.
644 DCHECK(message_loop_->BelongsToCurrentThread()); 594 DCHECK(message_loop_->BelongsToCurrentThread());
645 blocking_thread_.Stop(); 595 blocking_thread_.Stop();
596
597 StreamVector::iterator iter;
598 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
599 if (*iter)
600 (*iter)->Stop();
601 }
646 callback.Run(); 602 callback.Run();
647 } 603 }
648 604
649 void FFmpegDemuxer::DisableAudioStreamTask() { 605 void FFmpegDemuxer::DisableAudioStreamTask() {
650 DCHECK(message_loop_->BelongsToCurrentThread()); 606 DCHECK(message_loop_->BelongsToCurrentThread());
651 audio_disabled_ = true; 607 audio_disabled_ = true;
652 StreamVector::iterator iter; 608 StreamVector::iterator iter;
653 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 609 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
654 if (*iter && (*iter)->type() == DemuxerStream::AUDIO) { 610 if (*iter && (*iter)->type() == DemuxerStream::AUDIO) {
655 (*iter)->Stop(); 611 (*iter)->Stop();
(...skipping 17 matching lines...) Expand all
673 StreamVector::iterator iter; 629 StreamVector::iterator iter;
674 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 630 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
675 if (!*iter || 631 if (!*iter ||
676 (audio_disabled_ && (*iter)->type() == DemuxerStream::AUDIO)) { 632 (audio_disabled_ && (*iter)->type() == DemuxerStream::AUDIO)) {
677 continue; 633 continue;
678 } 634 }
679 (*iter)->EnqueuePacket(ScopedAVPacket()); 635 (*iter)->EnqueuePacket(ScopedAVPacket());
680 } 636 }
681 } 637 }
682 638
639 void FFmpegDemuxer::NotifyHasPendingRead() {
xhwang 2012/11/20 17:54:34 This function is only called once in SatisfyPendin
scherkus (not reviewing) 2012/11/20 19:16:07 I think it's fine keep around -- it's clearer than
640 DCHECK(message_loop_->BelongsToCurrentThread());
641 DemuxTask();
642 }
643
683 void FFmpegDemuxer::NotifyBufferingChanged() { 644 void FFmpegDemuxer::NotifyBufferingChanged() {
684 DCHECK(message_loop_->BelongsToCurrentThread()); 645 DCHECK(message_loop_->BelongsToCurrentThread());
685 Ranges<base::TimeDelta> buffered; 646 Ranges<base::TimeDelta> buffered;
686 scoped_refptr<FFmpegDemuxerStream> audio = 647 scoped_refptr<FFmpegDemuxerStream> audio =
687 audio_disabled_ ? NULL : GetFFmpegStream(DemuxerStream::AUDIO); 648 audio_disabled_ ? NULL : GetFFmpegStream(DemuxerStream::AUDIO);
688 scoped_refptr<FFmpegDemuxerStream> video = 649 scoped_refptr<FFmpegDemuxerStream> video =
689 GetFFmpegStream(DemuxerStream::VIDEO); 650 GetFFmpegStream(DemuxerStream::VIDEO);
690 if (audio && video) { 651 if (audio && video) {
691 buffered = audio->GetBufferedRanges().IntersectionWith( 652 buffered = audio->GetBufferedRanges().IntersectionWith(
692 video->GetBufferedRanges()); 653 video->GetBufferedRanges());
693 } else if (audio) { 654 } else if (audio) {
694 buffered = audio->GetBufferedRanges(); 655 buffered = audio->GetBufferedRanges();
695 } else if (video) { 656 } else if (video) {
696 buffered = video->GetBufferedRanges(); 657 buffered = video->GetBufferedRanges();
697 } 658 }
698 for (size_t i = 0; i < buffered.size(); ++i) 659 for (size_t i = 0; i < buffered.size(); ++i)
699 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i)); 660 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i));
700 } 661 }
701 662
702 void FFmpegDemuxer::OnDataSourceError() { 663 void FFmpegDemuxer::OnDataSourceError() {
703 host_->OnDemuxerError(PIPELINE_ERROR_READ); 664 host_->OnDemuxerError(PIPELINE_ERROR_READ);
704 } 665 }
705 666
706 } // namespace media 667 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698