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

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

Issue 13813016: Remove reference counting from media::Demuxer and friends. (Closed) Base URL: http://git.chromium.org/chromium/src.git@vd_scoped
Patch Set: Created 7 years, 8 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
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/base64.h" 10 #include "base/base64.h"
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 265
266 // 266 //
267 // FFmpegDemuxer 267 // FFmpegDemuxer
268 // 268 //
269 FFmpegDemuxer::FFmpegDemuxer( 269 FFmpegDemuxer::FFmpegDemuxer(
270 const scoped_refptr<base::MessageLoopProxy>& message_loop, 270 const scoped_refptr<base::MessageLoopProxy>& message_loop,
271 const scoped_refptr<DataSource>& data_source, 271 const scoped_refptr<DataSource>& data_source,
272 const FFmpegNeedKeyCB& need_key_cb) 272 const FFmpegNeedKeyCB& need_key_cb)
273 : host_(NULL), 273 : host_(NULL),
274 message_loop_(message_loop), 274 message_loop_(message_loop),
275 weak_factory_(this),
275 blocking_thread_("FFmpegDemuxer"), 276 blocking_thread_("FFmpegDemuxer"),
276 pending_read_(false), 277 pending_read_(false),
277 pending_seek_(false), 278 pending_seek_(false),
278 data_source_(data_source), 279 data_source_(data_source),
279 bitrate_(0), 280 bitrate_(0),
280 start_time_(kNoTimestamp()), 281 start_time_(kNoTimestamp()),
281 audio_disabled_(false), 282 audio_disabled_(false),
282 duration_known_(false), 283 duration_known_(false),
283 url_protocol_(data_source, BindToLoop(message_loop_, base::Bind( 284 url_protocol_(data_source, BindToLoop(message_loop_, base::Bind(
284 &FFmpegDemuxer::OnDataSourceError, base::Unretained(this)))), 285 &FFmpegDemuxer::OnDataSourceError, base::Unretained(this)))),
285 need_key_cb_(need_key_cb) { 286 need_key_cb_(need_key_cb) {
286 DCHECK(message_loop_); 287 DCHECK(message_loop_);
287 DCHECK(data_source_); 288 DCHECK(data_source_);
288 } 289 }
289 290
290 FFmpegDemuxer::~FFmpegDemuxer() {} 291 FFmpegDemuxer::~FFmpegDemuxer() {}
291 292
292 void FFmpegDemuxer::Stop(const base::Closure& callback) { 293 void FFmpegDemuxer::Stop(const base::Closure& callback) {
293 DCHECK(message_loop_->BelongsToCurrentThread()); 294 DCHECK(message_loop_->BelongsToCurrentThread());
294 url_protocol_.Abort(); 295 url_protocol_.Abort();
295 data_source_->Stop(BindToCurrentLoop(base::Bind( 296 data_source_->Stop(BindToCurrentLoop(base::Bind(
296 &FFmpegDemuxer::OnDataSourceStopped, this, BindToCurrentLoop(callback)))); 297 &FFmpegDemuxer::OnDataSourceStopped, weak_this_,
298 BindToCurrentLoop(callback))));
297 } 299 }
298 300
299 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { 301 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
300 DCHECK(message_loop_->BelongsToCurrentThread()); 302 DCHECK(message_loop_->BelongsToCurrentThread());
301 CHECK(!pending_seek_); 303 CHECK(!pending_seek_);
302 304
303 // TODO(scherkus): Inspect |pending_read_| and cancel IO via |blocking_url_|, 305 // TODO(scherkus): Inspect |pending_read_| and cancel IO via |blocking_url_|,
304 // otherwise we can end up waiting for a pre-seek read to complete even though 306 // otherwise we can end up waiting for a pre-seek read to complete even though
305 // we know we're going to drop it on the floor. 307 // we know we're going to drop it on the floor.
306 308
307 // Always seek to a timestamp less than or equal to the desired timestamp. 309 // Always seek to a timestamp less than or equal to the desired timestamp.
308 int flags = AVSEEK_FLAG_BACKWARD; 310 int flags = AVSEEK_FLAG_BACKWARD;
309 311
310 // Passing -1 as our stream index lets FFmpeg pick a default stream. FFmpeg 312 // Passing -1 as our stream index lets FFmpeg pick a default stream. FFmpeg
311 // will attempt to use the lowest-index video stream, if present, followed by 313 // will attempt to use the lowest-index video stream, if present, followed by
312 // the lowest-index audio stream. 314 // the lowest-index audio stream.
313 pending_seek_ = true; 315 pending_seek_ = true;
314 base::PostTaskAndReplyWithResult( 316 base::PostTaskAndReplyWithResult(
315 blocking_thread_.message_loop_proxy(), FROM_HERE, 317 blocking_thread_.message_loop_proxy(), FROM_HERE,
316 base::Bind(&av_seek_frame, glue_->format_context(), -1, 318 base::Bind(&av_seek_frame, glue_->format_context(), -1,
317 time.InMicroseconds(), flags), 319 time.InMicroseconds(), flags),
318 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, this, cb)); 320 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, weak_this_, cb));
319 } 321 }
320 322
321 void FFmpegDemuxer::SetPlaybackRate(float playback_rate) { 323 void FFmpegDemuxer::SetPlaybackRate(float playback_rate) {
322 DCHECK(message_loop_->BelongsToCurrentThread()); 324 DCHECK(message_loop_->BelongsToCurrentThread());
323 data_source_->SetPlaybackRate(playback_rate); 325 data_source_->SetPlaybackRate(playback_rate);
324 } 326 }
325 327
326 void FFmpegDemuxer::OnAudioRendererDisabled() { 328 void FFmpegDemuxer::OnAudioRendererDisabled() {
327 DCHECK(message_loop_->BelongsToCurrentThread()); 329 DCHECK(message_loop_->BelongsToCurrentThread());
328 audio_disabled_ = true; 330 audio_disabled_ = true;
329 StreamVector::iterator iter; 331 StreamVector::iterator iter;
330 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 332 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
331 if (*iter && (*iter)->type() == DemuxerStream::AUDIO) { 333 if (*iter && (*iter)->type() == DemuxerStream::AUDIO) {
332 (*iter)->Stop(); 334 (*iter)->Stop();
333 } 335 }
334 } 336 }
335 } 337 }
336 338
337 void FFmpegDemuxer::Initialize(DemuxerHost* host, 339 void FFmpegDemuxer::Initialize(DemuxerHost* host,
338 const PipelineStatusCB& status_cb) { 340 const PipelineStatusCB& status_cb) {
339 DCHECK(message_loop_->BelongsToCurrentThread()); 341 DCHECK(message_loop_->BelongsToCurrentThread());
340 host_ = host; 342 host_ = host;
343 weak_this_ = weak_factory_.GetWeakPtr();
acolwell GONE FROM CHROMIUM 2013/04/17 20:24:53 nit: Why is this deferred until here? Why not do t
scherkus (not reviewing) 2013/04/19 01:07:22 WeakPtr binds to thread it's created on. Since we
341 344
342 // TODO(scherkus): DataSource should have a host by this point, 345 // TODO(scherkus): DataSource should have a host by this point,
343 // see http://crbug.com/122071 346 // see http://crbug.com/122071
344 data_source_->set_host(host); 347 data_source_->set_host(host);
345 348
346 glue_.reset(new FFmpegGlue(&url_protocol_)); 349 glue_.reset(new FFmpegGlue(&url_protocol_));
347 AVFormatContext* format_context = glue_->format_context(); 350 AVFormatContext* format_context = glue_->format_context();
348 351
349 // Disable ID3v1 tag reading to avoid costly seeks to end of file for data we 352 // Disable ID3v1 tag reading to avoid costly seeks to end of file for data we
350 // don't use. FFmpeg will only read ID3v1 tags if no other metadata is 353 // don't use. FFmpeg will only read ID3v1 tags if no other metadata is
351 // available, so add a metadata entry to ensure some is always present. 354 // available, so add a metadata entry to ensure some is always present.
352 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0); 355 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0);
353 356
354 // Open the AVFormatContext using our glue layer. 357 // Open the AVFormatContext using our glue layer.
355 CHECK(blocking_thread_.Start()); 358 CHECK(blocking_thread_.Start());
356 base::PostTaskAndReplyWithResult( 359 base::PostTaskAndReplyWithResult(
357 blocking_thread_.message_loop_proxy(), FROM_HERE, 360 blocking_thread_.message_loop_proxy(), FROM_HERE,
358 base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())), 361 base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())),
359 base::Bind(&FFmpegDemuxer::OnOpenContextDone, this, status_cb)); 362 base::Bind(&FFmpegDemuxer::OnOpenContextDone, weak_this_, status_cb));
360 } 363 }
361 364
362 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream( 365 DemuxerStream* FFmpegDemuxer::GetStream(DemuxerStream::Type type) {
363 DemuxerStream::Type type) {
364 DCHECK(message_loop_->BelongsToCurrentThread()); 366 DCHECK(message_loop_->BelongsToCurrentThread());
365 return GetFFmpegStream(type); 367 return GetFFmpegStream(type);
366 } 368 }
367 369
368 scoped_refptr<FFmpegDemuxerStream> FFmpegDemuxer::GetFFmpegStream( 370 FFmpegDemuxerStream* FFmpegDemuxer::GetFFmpegStream(
369 DemuxerStream::Type type) const { 371 DemuxerStream::Type type) const {
370 StreamVector::const_iterator iter; 372 StreamVector::const_iterator iter;
371 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 373 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
372 if (*iter && (*iter)->type() == type) { 374 if (*iter && (*iter)->type() == type) {
373 return *iter; 375 return *iter;
374 } 376 }
375 } 377 }
376 return NULL; 378 return NULL;
377 } 379 }
378 380
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
428 if (!result) { 430 if (!result) {
429 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN); 431 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN);
430 return; 432 return;
431 } 433 }
432 434
433 // Fully initialize AVFormatContext by parsing the stream a little. 435 // Fully initialize AVFormatContext by parsing the stream a little.
434 base::PostTaskAndReplyWithResult( 436 base::PostTaskAndReplyWithResult(
435 blocking_thread_.message_loop_proxy(), FROM_HERE, 437 blocking_thread_.message_loop_proxy(), FROM_HERE,
436 base::Bind(&avformat_find_stream_info, glue_->format_context(), 438 base::Bind(&avformat_find_stream_info, glue_->format_context(),
437 static_cast<AVDictionary**>(NULL)), 439 static_cast<AVDictionary**>(NULL)),
438 base::Bind(&FFmpegDemuxer::OnFindStreamInfoDone, this, status_cb)); 440 base::Bind(&FFmpegDemuxer::OnFindStreamInfoDone, weak_this_, status_cb));
439 } 441 }
440 442
441 void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, 443 void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb,
442 int result) { 444 int result) {
443 DCHECK(message_loop_->BelongsToCurrentThread()); 445 DCHECK(message_loop_->BelongsToCurrentThread());
444 if (!blocking_thread_.IsRunning()) { 446 if (!blocking_thread_.IsRunning()) {
445 status_cb.Run(PIPELINE_ERROR_ABORT); 447 status_cb.Run(PIPELINE_ERROR_ABORT);
446 return; 448 return;
447 } 449 }
448 450
(...skipping 25 matching lines...) Expand all
474 continue; 476 continue;
475 // Ensure the codec is supported. 477 // Ensure the codec is supported.
476 if (CodecIDToVideoCodec(codec_context->codec_id) == kUnknownVideoCodec) 478 if (CodecIDToVideoCodec(codec_context->codec_id) == kUnknownVideoCodec)
477 continue; 479 continue;
478 found_video_stream = true; 480 found_video_stream = true;
479 } else { 481 } else {
480 continue; 482 continue;
481 } 483 }
482 484
483 AVStream* stream = format_context->streams[i]; 485 AVStream* stream = format_context->streams[i];
484 scoped_refptr<FFmpegDemuxerStream> demuxer_stream( 486 streams_[i] = new FFmpegDemuxerStream(this, stream);
485 new FFmpegDemuxerStream(this, stream)); 487 max_duration = std::max(max_duration, streams_[i]->duration());
486
487 streams_[i] = demuxer_stream;
488 max_duration = std::max(max_duration, demuxer_stream->duration());
489 488
490 if (stream->first_dts != static_cast<int64_t>(AV_NOPTS_VALUE)) { 489 if (stream->first_dts != static_cast<int64_t>(AV_NOPTS_VALUE)) {
491 const base::TimeDelta first_dts = ConvertFromTimeBase( 490 const base::TimeDelta first_dts = ConvertFromTimeBase(
492 stream->time_base, stream->first_dts); 491 stream->time_base, stream->first_dts);
493 if (start_time_ == kNoTimestamp() || first_dts < start_time_) 492 if (start_time_ == kNoTimestamp() || first_dts < start_time_)
494 start_time_ = first_dts; 493 start_time_ = first_dts;
495 } 494 }
496 } 495 }
497 496
498 if (!found_audio_stream && !found_video_stream) { 497 if (!found_audio_stream && !found_video_stream) {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 // Allocate and read an AVPacket from the media. Save |packet_ptr| since 578 // Allocate and read an AVPacket from the media. Save |packet_ptr| since
580 // evaluation order of packet.get() and base::Passed(&packet) is 579 // evaluation order of packet.get() and base::Passed(&packet) is
581 // undefined. 580 // undefined.
582 ScopedAVPacket packet(new AVPacket()); 581 ScopedAVPacket packet(new AVPacket());
583 AVPacket* packet_ptr = packet.get(); 582 AVPacket* packet_ptr = packet.get();
584 583
585 pending_read_ = true; 584 pending_read_ = true;
586 base::PostTaskAndReplyWithResult( 585 base::PostTaskAndReplyWithResult(
587 blocking_thread_.message_loop_proxy(), FROM_HERE, 586 blocking_thread_.message_loop_proxy(), FROM_HERE,
588 base::Bind(&av_read_frame, glue_->format_context(), packet_ptr), 587 base::Bind(&av_read_frame, glue_->format_context(), packet_ptr),
589 base::Bind(&FFmpegDemuxer::OnReadFrameDone, this, base::Passed(&packet))); 588 base::Bind(&FFmpegDemuxer::OnReadFrameDone, weak_this_,
589 base::Passed(&packet)));
590 } 590 }
591 591
592 void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) { 592 void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) {
593 DCHECK(message_loop_->BelongsToCurrentThread()); 593 DCHECK(message_loop_->BelongsToCurrentThread());
594 DCHECK(pending_read_); 594 DCHECK(pending_read_);
595 pending_read_ = false; 595 pending_read_ = false;
596 596
597 if (!blocking_thread_.IsRunning() || pending_seek_) { 597 if (!blocking_thread_.IsRunning() || pending_seek_) {
598 return; 598 return;
599 } 599 }
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
709 } 709 }
710 710
711 void FFmpegDemuxer::NotifyCapacityAvailable() { 711 void FFmpegDemuxer::NotifyCapacityAvailable() {
712 DCHECK(message_loop_->BelongsToCurrentThread()); 712 DCHECK(message_loop_->BelongsToCurrentThread());
713 ReadFrameIfNeeded(); 713 ReadFrameIfNeeded();
714 } 714 }
715 715
716 void FFmpegDemuxer::NotifyBufferingChanged() { 716 void FFmpegDemuxer::NotifyBufferingChanged() {
717 DCHECK(message_loop_->BelongsToCurrentThread()); 717 DCHECK(message_loop_->BelongsToCurrentThread());
718 Ranges<base::TimeDelta> buffered; 718 Ranges<base::TimeDelta> buffered;
719 scoped_refptr<FFmpegDemuxerStream> audio = 719 FFmpegDemuxerStream* audio =
720 audio_disabled_ ? NULL : GetFFmpegStream(DemuxerStream::AUDIO); 720 audio_disabled_ ? NULL : GetFFmpegStream(DemuxerStream::AUDIO);
721 scoped_refptr<FFmpegDemuxerStream> video = 721 FFmpegDemuxerStream* video = GetFFmpegStream(DemuxerStream::VIDEO);
722 GetFFmpegStream(DemuxerStream::VIDEO);
723 if (audio && video) { 722 if (audio && video) {
724 buffered = audio->GetBufferedRanges().IntersectionWith( 723 buffered = audio->GetBufferedRanges().IntersectionWith(
725 video->GetBufferedRanges()); 724 video->GetBufferedRanges());
726 } else if (audio) { 725 } else if (audio) {
727 buffered = audio->GetBufferedRanges(); 726 buffered = audio->GetBufferedRanges();
728 } else if (video) { 727 } else if (video) {
729 buffered = video->GetBufferedRanges(); 728 buffered = video->GetBufferedRanges();
730 } 729 }
731 for (size_t i = 0; i < buffered.size(); ++i) 730 for (size_t i = 0; i < buffered.size(); ++i)
732 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i)); 731 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i));
733 } 732 }
734 733
735 void FFmpegDemuxer::OnDataSourceError() { 734 void FFmpegDemuxer::OnDataSourceError() {
736 host_->OnDemuxerError(PIPELINE_ERROR_READ); 735 host_->OnDemuxerError(PIPELINE_ERROR_READ);
737 } 736 }
738 737
739 } // namespace media 738 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698