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

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

Issue 149475: Replaced DCHECKs to use MessageLoop::current() for FFmpegDemuxer and DecoderBase. (Closed)
Patch Set: Created 11 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
« no previous file with comments | « media/filters/ffmpeg_demuxer.h ('k') | media/filters/ffmpeg_video_decoder_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) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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 "base/scoped_ptr.h" 5 #include "base/scoped_ptr.h"
6 #include "base/stl_util-inl.h" 6 #include "base/stl_util-inl.h"
7 #include "base/string_util.h" 7 #include "base/string_util.h"
8 #include "base/time.h" 8 #include "base/time.h"
9 #include "media/base/filter_host.h" 9 #include "media/base/filter_host.h"
10 #include "media/filters/ffmpeg_common.h" 10 #include "media/filters/ffmpeg_common.h"
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 void* FFmpegDemuxerStream::QueryInterface(const char* id) { 103 void* FFmpegDemuxerStream::QueryInterface(const char* id) {
104 DCHECK(id); 104 DCHECK(id);
105 AVStreamProvider* interface_ptr = NULL; 105 AVStreamProvider* interface_ptr = NULL;
106 if (0 == strcmp(id, AVStreamProvider::interface_id())) { 106 if (0 == strcmp(id, AVStreamProvider::interface_id())) {
107 interface_ptr = this; 107 interface_ptr = this;
108 } 108 }
109 return interface_ptr; 109 return interface_ptr;
110 } 110 }
111 111
112 bool FFmpegDemuxerStream::HasPendingReads() { 112 bool FFmpegDemuxerStream::HasPendingReads() {
113 DCHECK_EQ(PlatformThread::CurrentId(), demuxer_->thread_id_); 113 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop());
114 DCHECK(!stopped_ || read_queue_.empty()) 114 DCHECK(!stopped_ || read_queue_.empty())
115 << "Read queue should have been emptied if demuxing stream is stopped"; 115 << "Read queue should have been emptied if demuxing stream is stopped";
116 return !read_queue_.empty(); 116 return !read_queue_.empty();
117 } 117 }
118 118
119 base::TimeDelta FFmpegDemuxerStream::EnqueuePacket(AVPacket* packet) { 119 base::TimeDelta FFmpegDemuxerStream::EnqueuePacket(AVPacket* packet) {
120 DCHECK_EQ(PlatformThread::CurrentId(), demuxer_->thread_id_); 120 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop());
121 base::TimeDelta timestamp = ConvertTimestamp(packet->pts); 121 base::TimeDelta timestamp = ConvertTimestamp(packet->pts);
122 base::TimeDelta duration = ConvertTimestamp(packet->duration); 122 base::TimeDelta duration = ConvertTimestamp(packet->duration);
123 if (stopped_) { 123 if (stopped_) {
124 NOTREACHED() << "Attempted to enqueue packet on a stopped stream"; 124 NOTREACHED() << "Attempted to enqueue packet on a stopped stream";
125 return timestamp; 125 return timestamp;
126 } 126 }
127 127
128 // Enqueue the callback and attempt to satisfy a read immediately. 128 // Enqueue the callback and attempt to satisfy a read immediately.
129 scoped_refptr<Buffer> buffer = 129 scoped_refptr<Buffer> buffer =
130 new AVPacketBuffer(packet, timestamp, duration); 130 new AVPacketBuffer(packet, timestamp, duration);
131 if (!buffer) { 131 if (!buffer) {
132 NOTREACHED() << "Unable to allocate AVPacketBuffer"; 132 NOTREACHED() << "Unable to allocate AVPacketBuffer";
133 return timestamp; 133 return timestamp;
134 } 134 }
135 buffer_queue_.push_back(buffer); 135 buffer_queue_.push_back(buffer);
136 FulfillPendingRead(); 136 FulfillPendingRead();
137 return timestamp; 137 return timestamp;
138 } 138 }
139 139
140 void FFmpegDemuxerStream::FlushBuffers() { 140 void FFmpegDemuxerStream::FlushBuffers() {
141 DCHECK_EQ(PlatformThread::CurrentId(), demuxer_->thread_id_); 141 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop());
142 buffer_queue_.clear(); 142 buffer_queue_.clear();
143 discontinuous_ = true; 143 discontinuous_ = true;
144 } 144 }
145 145
146 void FFmpegDemuxerStream::Stop() { 146 void FFmpegDemuxerStream::Stop() {
147 DCHECK_EQ(PlatformThread::CurrentId(), demuxer_->thread_id_); 147 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop());
148 buffer_queue_.clear(); 148 buffer_queue_.clear();
149 STLDeleteElements(&read_queue_); 149 STLDeleteElements(&read_queue_);
150 stopped_ = true; 150 stopped_ = true;
151 } 151 }
152 152
153 const MediaFormat& FFmpegDemuxerStream::media_format() { 153 const MediaFormat& FFmpegDemuxerStream::media_format() {
154 return media_format_; 154 return media_format_;
155 } 155 }
156 156
157 void FFmpegDemuxerStream::Read(Callback1<Buffer*>::Type* read_callback) { 157 void FFmpegDemuxerStream::Read(Callback1<Buffer*>::Type* read_callback) {
158 DCHECK(read_callback); 158 DCHECK(read_callback);
159 demuxer_->message_loop()->PostTask(FROM_HERE, 159 demuxer_->message_loop()->PostTask(FROM_HERE,
160 NewRunnableMethod(this, &FFmpegDemuxerStream::ReadTask, read_callback)); 160 NewRunnableMethod(this, &FFmpegDemuxerStream::ReadTask, read_callback));
161 } 161 }
162 162
163 void FFmpegDemuxerStream::ReadTask(Callback1<Buffer*>::Type* read_callback) { 163 void FFmpegDemuxerStream::ReadTask(Callback1<Buffer*>::Type* read_callback) {
164 DCHECK_EQ(PlatformThread::CurrentId(), demuxer_->thread_id_); 164 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop());
165 165
166 // Don't accept any additional reads if we've been told to stop. 166 // Don't accept any additional reads if we've been told to stop.
167 // 167 //
168 // TODO(scherkus): it would be cleaner if we replied with an error message. 168 // TODO(scherkus): it would be cleaner if we replied with an error message.
169 if (stopped_) { 169 if (stopped_) {
170 delete read_callback; 170 delete read_callback;
171 return; 171 return;
172 } 172 }
173 173
174 // Enqueue the callback and attempt to satisfy it immediately. 174 // Enqueue the callback and attempt to satisfy it immediately.
175 read_queue_.push_back(read_callback); 175 read_queue_.push_back(read_callback);
176 FulfillPendingRead(); 176 FulfillPendingRead();
177 177
178 // There are still pending reads, demux some more. 178 // There are still pending reads, demux some more.
179 if (HasPendingReads()) { 179 if (HasPendingReads()) {
180 demuxer_->PostDemuxTask(); 180 demuxer_->PostDemuxTask();
181 } 181 }
182 } 182 }
183 183
184 void FFmpegDemuxerStream::FulfillPendingRead() { 184 void FFmpegDemuxerStream::FulfillPendingRead() {
185 DCHECK_EQ(PlatformThread::CurrentId(), demuxer_->thread_id_); 185 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop());
186 if (buffer_queue_.empty() || read_queue_.empty()) { 186 if (buffer_queue_.empty() || read_queue_.empty()) {
187 return; 187 return;
188 } 188 }
189 189
190 // Dequeue a buffer and pending read pair. 190 // Dequeue a buffer and pending read pair.
191 scoped_refptr<Buffer> buffer = buffer_queue_.front(); 191 scoped_refptr<Buffer> buffer = buffer_queue_.front();
192 scoped_ptr<Callback1<Buffer*>::Type> read_callback(read_queue_.front()); 192 scoped_ptr<Callback1<Buffer*>::Type> read_callback(read_queue_.front());
193 buffer_queue_.pop_front(); 193 buffer_queue_.pop_front();
194 read_queue_.pop_front(); 194 read_queue_.pop_front();
195 195
(...skipping 12 matching lines...) Expand all
208 base::TimeDelta FFmpegDemuxerStream::ConvertTimestamp(int64 timestamp) { 208 base::TimeDelta FFmpegDemuxerStream::ConvertTimestamp(int64 timestamp) {
209 AVRational time_base = { 1, base::Time::kMicrosecondsPerSecond }; 209 AVRational time_base = { 1, base::Time::kMicrosecondsPerSecond };
210 int64 microseconds = av_rescale_q(timestamp, stream_->time_base, time_base); 210 int64 microseconds = av_rescale_q(timestamp, stream_->time_base, time_base);
211 return base::TimeDelta::FromMicroseconds(microseconds); 211 return base::TimeDelta::FromMicroseconds(microseconds);
212 } 212 }
213 213
214 // 214 //
215 // FFmpegDemuxer 215 // FFmpegDemuxer
216 // 216 //
217 FFmpegDemuxer::FFmpegDemuxer() 217 FFmpegDemuxer::FFmpegDemuxer()
218 : format_context_(NULL), 218 : format_context_(NULL) {
219 thread_id_(NULL) {
220 } 219 }
221 220
222 FFmpegDemuxer::~FFmpegDemuxer() { 221 FFmpegDemuxer::~FFmpegDemuxer() {
223 // In this destructor, we clean up resources held by FFmpeg. It is ugly to 222 // In this destructor, we clean up resources held by FFmpeg. It is ugly to
224 // close the codec contexts here because the corresponding codecs are opened 223 // close the codec contexts here because the corresponding codecs are opened
225 // in the decoder filters. By reaching this point, all filters should have 224 // in the decoder filters. By reaching this point, all filters should have
226 // stopped, so this is the only safe place to do the global clean up. 225 // stopped, so this is the only safe place to do the global clean up.
227 // TODO(hclam): close the codecs in the corresponding decoders. 226 // TODO(hclam): close the codecs in the corresponding decoders.
228 AutoLock auto_lock(FFmpegLock::get()->lock()); 227 AutoLock auto_lock(FFmpegLock::get()->lock());
229 if (!format_context_) 228 if (!format_context_)
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
281 return streams_.size(); 280 return streams_.size();
282 } 281 }
283 282
284 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream(int stream) { 283 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream(int stream) {
285 DCHECK(stream >= 0); 284 DCHECK(stream >= 0);
286 DCHECK(stream < static_cast<int>(streams_.size())); 285 DCHECK(stream < static_cast<int>(streams_.size()));
287 return streams_[stream].get(); 286 return streams_[stream].get();
288 } 287 }
289 288
290 void FFmpegDemuxer::InititalizeTask(DataSource* data_source) { 289 void FFmpegDemuxer::InititalizeTask(DataSource* data_source) {
290 DCHECK_EQ(MessageLoop::current(), message_loop());
291
291 // In order to get FFmpeg to use |data_source| for file IO we must transfer 292 // In order to get FFmpeg to use |data_source| for file IO we must transfer
292 // ownership via FFmpegGlue. We'll add |data_source| to FFmpegGlue and pass 293 // ownership via FFmpegGlue. We'll add |data_source| to FFmpegGlue and pass
293 // the resulting key to FFmpeg. FFmpeg will pass the key to FFmpegGlue which 294 // the resulting key to FFmpeg. FFmpeg will pass the key to FFmpegGlue which
294 // will take care of attaching |data_source| to an FFmpeg context. After 295 // will take care of attaching |data_source| to an FFmpeg context. After
295 // we finish initializing the FFmpeg context we can remove |data_source| from 296 // we finish initializing the FFmpeg context we can remove |data_source| from
296 // FFmpegGlue. 297 // FFmpegGlue.
297 // 298 //
298 // Refer to media/filters/ffmpeg_glue.h for details. 299 // Refer to media/filters/ffmpeg_glue.h for details.
299 300
300 // Grab the thread id for debugging.
301 DCHECK(!thread_id_);
302 thread_id_ = PlatformThread::CurrentId();
303
304 // Add our data source and get our unique key. 301 // Add our data source and get our unique key.
305 std::string key = FFmpegGlue::get()->AddDataSource(data_source); 302 std::string key = FFmpegGlue::get()->AddDataSource(data_source);
306 303
307 // Open FFmpeg AVFormatContext. 304 // Open FFmpeg AVFormatContext.
308 DCHECK(!format_context_); 305 DCHECK(!format_context_);
309 AVFormatContext* context = NULL; 306 AVFormatContext* context = NULL;
310 int result = av_open_input_file(&context, key.c_str(), NULL, 0, NULL); 307 int result = av_open_input_file(&context, key.c_str(), NULL, 0, NULL);
311 308
312 // Remove our data source. 309 // Remove our data source.
313 FFmpegGlue::get()->RemoveDataSource(data_source); 310 FFmpegGlue::get()->RemoveDataSource(data_source);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 host()->Error(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); 349 host()->Error(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
353 return; 350 return;
354 } 351 }
355 352
356 // Good to go: set the duration and notify we're done initializing. 353 // Good to go: set the duration and notify we're done initializing.
357 host()->SetDuration(max_duration); 354 host()->SetDuration(max_duration);
358 host()->InitializationComplete(); 355 host()->InitializationComplete();
359 } 356 }
360 357
361 void FFmpegDemuxer::SeekTask(base::TimeDelta time) { 358 void FFmpegDemuxer::SeekTask(base::TimeDelta time) {
362 DCHECK_EQ(PlatformThread::CurrentId(), thread_id_); 359 DCHECK_EQ(MessageLoop::current(), message_loop());
363 360
364 // Tell streams to flush buffers due to seeking. 361 // Tell streams to flush buffers due to seeking.
365 StreamVector::iterator iter; 362 StreamVector::iterator iter;
366 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 363 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
367 (*iter)->FlushBuffers(); 364 (*iter)->FlushBuffers();
368 } 365 }
369 366
370 // Seek backwards if requested timestamp is behind FFmpeg's current time. 367 // Seek backwards if requested timestamp is behind FFmpeg's current time.
371 int flags = 0; 368 int flags = 0;
372 if (time <= current_timestamp_) { 369 if (time <= current_timestamp_) {
373 flags |= AVSEEK_FLAG_BACKWARD; 370 flags |= AVSEEK_FLAG_BACKWARD;
374 } 371 }
375 372
376 if (av_seek_frame(format_context_, -1, time.InMicroseconds(), 373 if (av_seek_frame(format_context_, -1, time.InMicroseconds(),
377 flags) < 0) { 374 flags) < 0) {
378 // TODO(scherkus): signal error. 375 // TODO(scherkus): signal error.
379 NOTIMPLEMENTED(); 376 NOTIMPLEMENTED();
380 } 377 }
381 } 378 }
382 379
383 void FFmpegDemuxer::DemuxTask() { 380 void FFmpegDemuxer::DemuxTask() {
384 DCHECK_EQ(PlatformThread::CurrentId(), thread_id_); 381 DCHECK_EQ(MessageLoop::current(), message_loop());
385 382
386 // Make sure we have work to do before demuxing. 383 // Make sure we have work to do before demuxing.
387 if (!StreamsHavePendingReads()) { 384 if (!StreamsHavePendingReads()) {
388 return; 385 return;
389 } 386 }
390 387
391 // Allocate and read an AVPacket from the media. 388 // Allocate and read an AVPacket from the media.
392 scoped_ptr<AVPacket> packet(new AVPacket()); 389 scoped_ptr<AVPacket> packet(new AVPacket());
393 int result = av_read_frame(format_context_, packet.get()); 390 int result = av_read_frame(format_context_, packet.get());
394 if (result < 0) { 391 if (result < 0) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 } 428 }
432 429
433 // Create a loop by posting another task. This allows seek and message loop 430 // Create a loop by posting another task. This allows seek and message loop
434 // quit tasks to get processed. 431 // quit tasks to get processed.
435 if (StreamsHavePendingReads()) { 432 if (StreamsHavePendingReads()) {
436 PostDemuxTask(); 433 PostDemuxTask();
437 } 434 }
438 } 435 }
439 436
440 void FFmpegDemuxer::StopTask() { 437 void FFmpegDemuxer::StopTask() {
441 DCHECK_EQ(PlatformThread::CurrentId(), thread_id_); 438 DCHECK_EQ(MessageLoop::current(), message_loop());
442 StreamVector::iterator iter; 439 StreamVector::iterator iter;
443 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 440 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
444 (*iter)->Stop(); 441 (*iter)->Stop();
445 } 442 }
446 } 443 }
447 444
448 bool FFmpegDemuxer::StreamsHavePendingReads() { 445 bool FFmpegDemuxer::StreamsHavePendingReads() {
449 DCHECK_EQ(PlatformThread::CurrentId(), thread_id_); 446 DCHECK_EQ(MessageLoop::current(), message_loop());
450 StreamVector::iterator iter; 447 StreamVector::iterator iter;
451 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 448 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
452 if ((*iter)->HasPendingReads()) { 449 if ((*iter)->HasPendingReads()) {
453 return true; 450 return true;
454 } 451 }
455 } 452 }
456 return false; 453 return false;
457 } 454 }
458 455
459 void FFmpegDemuxer::StreamHasEnded() { 456 void FFmpegDemuxer::StreamHasEnded() {
460 DCHECK_EQ(PlatformThread::CurrentId(), thread_id_); 457 DCHECK_EQ(MessageLoop::current(), message_loop());
461 StreamVector::iterator iter; 458 StreamVector::iterator iter;
462 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 459 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
463 AVPacket* packet = new AVPacket(); 460 AVPacket* packet = new AVPacket();
464 memset(packet, 0, sizeof(*packet)); 461 memset(packet, 0, sizeof(*packet));
465 (*iter)->EnqueuePacket(packet); 462 (*iter)->EnqueuePacket(packet);
466 } 463 }
467 } 464 }
468 465
469 } // namespace media 466 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/ffmpeg_demuxer.h ('k') | media/filters/ffmpeg_video_decoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698