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

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

Issue 8890071: Stop audio FFmpegDemuxerStreams if we get notified that audio rendering is disabled. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src
Patch Set: foo Created 9 years 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 | « media/filters/ffmpeg_demuxer.h ('k') | media/filters/ffmpeg_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 #include "base/bind.h" 5 #include "base/bind.h"
6 #include "base/callback.h" 6 #include "base/callback.h"
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/memory/scoped_ptr.h" 8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 const PipelineStatusCB& callback) { 355 const PipelineStatusCB& callback) {
356 message_loop_->PostTask( 356 message_loop_->PostTask(
357 FROM_HERE, 357 FROM_HERE,
358 base::Bind(&FFmpegDemuxer::InitializeTask, this, 358 base::Bind(&FFmpegDemuxer::InitializeTask, this,
359 make_scoped_refptr(data_source), 359 make_scoped_refptr(data_source),
360 callback)); 360 callback));
361 } 361 }
362 362
363 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream( 363 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream(
364 DemuxerStream::Type type) { 364 DemuxerStream::Type type) {
365 DCHECK_GE(type, 0); 365 StreamVector::iterator iter;
366 DCHECK_LT(type, DemuxerStream::NUM_TYPES); 366 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
367 return streams_[type]; 367 if (*iter && (*iter)->type() == type) {
368 return *iter;
369 }
370 }
371 return NULL;
368 } 372 }
369 373
370 base::TimeDelta FFmpegDemuxer::GetStartTime() const { 374 base::TimeDelta FFmpegDemuxer::GetStartTime() const {
371 return start_time_; 375 return start_time_;
372 } 376 }
373 377
374 size_t FFmpegDemuxer::Read(size_t size, uint8* data) { 378 size_t FFmpegDemuxer::Read(size_t size, uint8* data) {
375 DCHECK(data_source_); 379 DCHECK(data_source_);
376 380
377 // If read has ever failed, return with an error. 381 // If read has ever failed, return with an error.
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
472 DCHECK(context); 476 DCHECK(context);
473 format_context_ = context; 477 format_context_ = context;
474 478
475 // Fully initialize AVFormatContext by parsing the stream a little. 479 // Fully initialize AVFormatContext by parsing the stream a little.
476 result = av_find_stream_info(format_context_); 480 result = av_find_stream_info(format_context_);
477 if (result < 0) { 481 if (result < 0) {
478 callback.Run(DEMUXER_ERROR_COULD_NOT_PARSE); 482 callback.Run(DEMUXER_ERROR_COULD_NOT_PARSE);
479 return; 483 return;
480 } 484 }
481 485
482 // Create demuxer streams for all supported streams. 486 // Create demuxer stream entries for each possible AVStream.
483 streams_.resize(DemuxerStream::NUM_TYPES); 487 streams_.resize(format_context_->nb_streams);
488 bool found_audio_stream = false;
489 bool found_video_stream = false;
490
484 base::TimeDelta max_duration; 491 base::TimeDelta max_duration;
485 bool no_supported_streams = true;
486 for (size_t i = 0; i < format_context_->nb_streams; ++i) { 492 for (size_t i = 0; i < format_context_->nb_streams; ++i) {
487 AVCodecContext* codec_context = format_context_->streams[i]->codec; 493 AVCodecContext* codec_context = format_context_->streams[i]->codec;
488 AVMediaType codec_type = codec_context->codec_type; 494 AVMediaType codec_type = codec_context->codec_type;
489 if (codec_type == AVMEDIA_TYPE_AUDIO || codec_type == AVMEDIA_TYPE_VIDEO) {
490 AVStream* stream = format_context_->streams[i];
491 scoped_refptr<FFmpegDemuxerStream> demuxer_stream(
492 new FFmpegDemuxerStream(this, stream));
493 if (!streams_[demuxer_stream->type()]) {
494 no_supported_streams = false;
495 streams_[demuxer_stream->type()] = demuxer_stream;
496 max_duration = std::max(max_duration, demuxer_stream->duration());
497 495
498 if (stream->first_dts != static_cast<int64_t>(AV_NOPTS_VALUE)) { 496 if (codec_type == AVMEDIA_TYPE_AUDIO) {
499 const base::TimeDelta first_dts = ConvertFromTimeBase( 497 if (found_audio_stream)
500 stream->time_base, stream->first_dts); 498 continue;
501 if (start_time_ == kNoTimestamp || first_dts < start_time_) 499 found_audio_stream = true;
502 start_time_ = first_dts; 500 } else if (codec_type == AVMEDIA_TYPE_VIDEO) {
503 } 501 if (found_video_stream)
504 } 502 continue;
505 packet_streams_.push_back(demuxer_stream); 503 found_video_stream = true;
506 } else { 504 } else {
507 packet_streams_.push_back(NULL); 505 continue;
506 }
507
508 AVStream* stream = format_context_->streams[i];
509 scoped_refptr<FFmpegDemuxerStream> demuxer_stream(
510 new FFmpegDemuxerStream(this, stream));
511
512 streams_[i] = demuxer_stream;
513 max_duration = std::max(max_duration, demuxer_stream->duration());
514
515 if (stream->first_dts != static_cast<int64_t>(AV_NOPTS_VALUE)) {
516 const base::TimeDelta first_dts = ConvertFromTimeBase(
517 stream->time_base, stream->first_dts);
518 if (start_time_ == kNoTimestamp || first_dts < start_time_)
519 start_time_ = first_dts;
508 } 520 }
509 } 521 }
510 if (no_supported_streams) { 522
523 if (!found_audio_stream && !found_video_stream) {
511 callback.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); 524 callback.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
512 return; 525 return;
513 } 526 }
527
514 if (format_context_->duration != static_cast<int64_t>(AV_NOPTS_VALUE)) { 528 if (format_context_->duration != static_cast<int64_t>(AV_NOPTS_VALUE)) {
515 // If there is a duration value in the container use that to find the 529 // If there is a duration value in the container use that to find the
516 // maximum between it and the duration from A/V streams. 530 // maximum between it and the duration from A/V streams.
517 const AVRational av_time_base = {1, AV_TIME_BASE}; 531 const AVRational av_time_base = {1, AV_TIME_BASE};
518 max_duration = 532 max_duration =
519 std::max(max_duration, 533 std::max(max_duration,
520 ConvertFromTimeBase(av_time_base, format_context_->duration)); 534 ConvertFromTimeBase(av_time_base, format_context_->duration));
521 } else { 535 } else {
522 // The duration is unknown, in which case this is likely a live stream. 536 // The duration is unknown, in which case this is likely a live stream.
523 max_duration = kInfiniteDuration; 537 max_duration = kInfiniteDuration;
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
635 // the event. 649 // the event.
636 StreamHasEnded(); 650 StreamHasEnded();
637 return; 651 return;
638 } 652 }
639 653
640 // Queue the packet with the appropriate stream. 654 // Queue the packet with the appropriate stream.
641 // TODO(scherkus): should we post this back to the pipeline thread? I'm 655 // TODO(scherkus): should we post this back to the pipeline thread? I'm
642 // worried about downstream filters (i.e., decoders) executing on this 656 // worried about downstream filters (i.e., decoders) executing on this
643 // thread. 657 // thread.
644 DCHECK_GE(packet->stream_index, 0); 658 DCHECK_GE(packet->stream_index, 0);
645 DCHECK_LT(packet->stream_index, static_cast<int>(packet_streams_.size())); 659 DCHECK_LT(packet->stream_index, static_cast<int>(streams_.size()));
646 FFmpegDemuxerStream* demuxer_stream = NULL; 660
647 size_t i = packet->stream_index;
648 // Defend against ffmpeg giving us a bad stream index. 661 // Defend against ffmpeg giving us a bad stream index.
649 if (i < packet_streams_.size()) { 662 if (packet->stream_index >= 0 &&
650 demuxer_stream = packet_streams_[i]; 663 packet->stream_index < static_cast<int>(streams_.size()) &&
651 } 664 streams_[packet->stream_index]) {
652 if (demuxer_stream) { 665 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index];
653 // Queue the packet with the appropriate stream. The stream takes 666
654 // ownership of the AVPacket. 667 // If a packet is returned by FFmpeg's av_parser_parse2()
655 if (packet.get()) { 668 // the packet will reference an inner memory of FFmpeg.
656 // If a packet is returned by FFmpeg's av_parser_parse2() 669 // In this case, the packet's "destruct" member is NULL,
657 // the packet will reference an inner memory of FFmpeg. 670 // and it MUST be duplicated. This fixes issue with MP3 and possibly
658 // In this case, the packet's "destruct" member is NULL, 671 // other codecs. It is safe to call this function even if the packet does
659 // and it MUST be duplicated. This fixes issue with MP3 and possibly 672 // not refer to inner memory from FFmpeg.
660 // other codecs. It is safe to call this function even if the packet does 673 av_dup_packet(packet.get());
661 // not refer to inner memory from FFmpeg. 674
662 av_dup_packet(packet.get()); 675 // The stream takes ownership of the AVPacket.
663 demuxer_stream->EnqueuePacket(packet.release()); 676 demuxer_stream->EnqueuePacket(packet.release());
664 }
665 } 677 }
666 678
667 // Create a loop by posting another task. This allows seek and message loop 679 // Create a loop by posting another task. This allows seek and message loop
668 // quit tasks to get processed. 680 // quit tasks to get processed.
669 if (StreamsHavePendingReads()) { 681 if (StreamsHavePendingReads()) {
670 PostDemuxTask(); 682 PostDemuxTask();
671 } 683 }
672 } 684 }
673 685
674 void FFmpegDemuxer::StopTask(const base::Closure& callback) { 686 void FFmpegDemuxer::StopTask(const base::Closure& callback) {
675 DCHECK_EQ(MessageLoop::current(), message_loop_); 687 DCHECK_EQ(MessageLoop::current(), message_loop_);
676 StreamVector::iterator iter; 688 StreamVector::iterator iter;
677 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 689 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
678 if (*iter) 690 if (*iter)
679 (*iter)->Stop(); 691 (*iter)->Stop();
680 } 692 }
681 if (data_source_) { 693 if (data_source_) {
682 data_source_->Stop(callback); 694 data_source_->Stop(callback);
683 } else { 695 } else {
684 callback.Run(); 696 callback.Run();
685 } 697 }
686 } 698 }
687 699
688 void FFmpegDemuxer::DisableAudioStreamTask() { 700 void FFmpegDemuxer::DisableAudioStreamTask() {
689 DCHECK_EQ(MessageLoop::current(), message_loop_); 701 DCHECK_EQ(MessageLoop::current(), message_loop_);
690
691 StreamVector::iterator iter; 702 StreamVector::iterator iter;
692 for (size_t i = 0; i < packet_streams_.size(); ++i) { 703 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
693 if (!packet_streams_[i]) 704 if (*iter && (*iter)->type() == DemuxerStream::AUDIO) {
694 continue; 705 (*iter)->Stop();
695
696 // If the codec type is audio, remove the reference. DemuxTask() will
697 // look for such reference, and this will result in deleting the
698 // audio packets after they are demuxed.
699 if (packet_streams_[i]->type() == DemuxerStream::AUDIO) {
700 packet_streams_[i] = NULL;
701 } 706 }
702 } 707 }
703 } 708 }
704 709
705 bool FFmpegDemuxer::StreamsHavePendingReads() { 710 bool FFmpegDemuxer::StreamsHavePendingReads() {
706 DCHECK_EQ(MessageLoop::current(), message_loop_); 711 DCHECK_EQ(MessageLoop::current(), message_loop_);
707 StreamVector::iterator iter; 712 StreamVector::iterator iter;
708 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 713 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
709 if (*iter && (*iter)->HasPendingReads()) { 714 if (*iter && (*iter)->HasPendingReads()) {
710 return true; 715 return true;
(...skipping 22 matching lines...) Expand all
733 read_event_.Wait(); 738 read_event_.Wait();
734 return last_read_bytes_; 739 return last_read_bytes_;
735 } 740 }
736 741
737 void FFmpegDemuxer::SignalReadCompleted(size_t size) { 742 void FFmpegDemuxer::SignalReadCompleted(size_t size) {
738 last_read_bytes_ = size; 743 last_read_bytes_ = size;
739 read_event_.Signal(); 744 read_event_.Signal();
740 } 745 }
741 746
742 } // namespace media 747 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/ffmpeg_demuxer.h ('k') | media/filters/ffmpeg_demuxer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698