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

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

Issue 353563002: Fix corrupted audio and video at playback start in ogg containers. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Oggify. Created 6 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 | 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) 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 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
77 } 77 }
78 78
79 // NOTE: Do not use AVStream->first_dts since |start_time| should be a 79 // NOTE: Do not use AVStream->first_dts since |start_time| should be a
80 // presentation timestamp. 80 // presentation timestamp.
81 return start_time; 81 return start_time;
82 } 82 }
83 83
84 // 84 //
85 // FFmpegDemuxerStream 85 // FFmpegDemuxerStream
86 // 86 //
87 FFmpegDemuxerStream::FFmpegDemuxerStream( 87 FFmpegDemuxerStream::FFmpegDemuxerStream(FFmpegDemuxer* demuxer,
88 FFmpegDemuxer* demuxer, 88 AVStream* stream)
89 AVStream* stream,
90 bool discard_negative_timestamps)
91 : demuxer_(demuxer), 89 : demuxer_(demuxer),
92 task_runner_(base::MessageLoopProxy::current()), 90 task_runner_(base::MessageLoopProxy::current()),
93 stream_(stream), 91 stream_(stream),
94 type_(UNKNOWN), 92 type_(UNKNOWN),
95 end_of_stream_(false), 93 end_of_stream_(false),
96 last_packet_timestamp_(kNoTimestamp()), 94 last_packet_timestamp_(kNoTimestamp()),
97 bitstream_converter_enabled_(false), 95 bitstream_converter_enabled_(false),
98 discard_negative_timestamps_(discard_negative_timestamps) { 96 fixup_negative_ogg_timestamps_(false) {
99 DCHECK(demuxer_); 97 DCHECK(demuxer_);
100 98
101 bool is_encrypted = false; 99 bool is_encrypted = false;
102 100
103 // Determine our media format. 101 // Determine our media format.
104 switch (stream->codec->codec_type) { 102 switch (stream->codec->codec_type) {
105 case AVMEDIA_TYPE_AUDIO: 103 case AVMEDIA_TYPE_AUDIO:
106 type_ = AUDIO; 104 type_ = AUDIO;
107 AVStreamToAudioDecoderConfig(stream, &audio_config_, true); 105 AVStreamToAudioDecoderConfig(stream, &audio_config_, true);
108 is_encrypted = audio_config_.is_encrypted(); 106 is_encrypted = audio_config_.is_encrypted();
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 } 253 }
256 254
257 buffer->set_duration( 255 buffer->set_duration(
258 ConvertStreamTimestamp(stream_->time_base, packet->duration)); 256 ConvertStreamTimestamp(stream_->time_base, packet->duration));
259 257
260 // Note: If pts is AV_NOPTS_VALUE, stream_timestamp will be kNoTimestamp(). 258 // Note: If pts is AV_NOPTS_VALUE, stream_timestamp will be kNoTimestamp().
261 const base::TimeDelta stream_timestamp = 259 const base::TimeDelta stream_timestamp =
262 ConvertStreamTimestamp(stream_->time_base, packet->pts); 260 ConvertStreamTimestamp(stream_->time_base, packet->pts);
263 261
264 if (stream_timestamp != kNoTimestamp()) { 262 if (stream_timestamp != kNoTimestamp()) {
265 buffer->set_timestamp(stream_timestamp - demuxer_->start_time()); 263 // If this is an OGG file with negative timestamps don't rebase any other
264 // stream types against the negative starting time.
265 base::TimeDelta start_time = demuxer_->start_time();
266 if (fixup_negative_ogg_timestamps_ && type() != AUDIO &&
267 start_time < base::TimeDelta()) {
268 DCHECK(stream_timestamp >= base::TimeDelta());
269 start_time = base::TimeDelta();
270 }
271
272 buffer->set_timestamp(stream_timestamp - start_time);
266 273
267 // If enabled, mark packets with negative timestamps for post-decode 274 // If enabled, mark packets with negative timestamps for post-decode
268 // discard. 275 // discard.
269 if (discard_negative_timestamps_ && stream_timestamp < base::TimeDelta()) { 276 if (fixup_negative_ogg_timestamps_ &&
277 stream_timestamp < base::TimeDelta()) {
270 if (stream_timestamp + buffer->duration() < base::TimeDelta()) { 278 if (stream_timestamp + buffer->duration() < base::TimeDelta()) {
271 // Discard the entire packet if it's entirely before zero. 279 // Discard the entire packet if it's entirely before zero.
272 buffer->set_discard_padding( 280 buffer->set_discard_padding(
273 std::make_pair(kInfiniteDuration(), base::TimeDelta())); 281 std::make_pair(kInfiniteDuration(), base::TimeDelta()));
274 } else { 282 } else {
275 // Only discard part of the frame if it overlaps zero. 283 // Only discard part of the frame if it overlaps zero.
276 buffer->set_discard_padding( 284 buffer->set_discard_padding(
277 std::make_pair(-stream_timestamp, base::TimeDelta())); 285 std::make_pair(-stream_timestamp, base::TimeDelta()));
278 } 286 }
279 } 287 }
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
495 DCHECK(task_runner_->BelongsToCurrentThread()); 503 DCHECK(task_runner_->BelongsToCurrentThread());
496 CHECK(!pending_seek_); 504 CHECK(!pending_seek_);
497 505
498 // TODO(scherkus): Inspect |pending_read_| and cancel IO via |blocking_url_|, 506 // TODO(scherkus): Inspect |pending_read_| and cancel IO via |blocking_url_|,
499 // otherwise we can end up waiting for a pre-seek read to complete even though 507 // otherwise we can end up waiting for a pre-seek read to complete even though
500 // we know we're going to drop it on the floor. 508 // we know we're going to drop it on the floor.
501 509
502 // FFmpeg requires seeks to be adjusted according to the lowest starting time. 510 // FFmpeg requires seeks to be adjusted according to the lowest starting time.
503 const base::TimeDelta seek_time = time + start_time_; 511 const base::TimeDelta seek_time = time + start_time_;
504 512
505 // Choose the preferred stream if |seek_time| occurs after its starting time, 513 // Choose the seeking stream based on whether it contains the seek time, if no
506 // otherwise use the fallback stream. 514 // match can be found prefer the preferred stream.
507 DCHECK(preferred_stream_for_seeking_.second != kNoTimestamp()); 515 DCHECK(preferred_stream_for_seeking_.second != kNoTimestamp());
508 const int stream_index = seek_time >= preferred_stream_for_seeking_.second 516 const int stream_index =
509 ? preferred_stream_for_seeking_.first 517 seek_time < preferred_stream_for_seeking_.second &&
510 : fallback_stream_for_seeking_.first; 518 seek_time >= fallback_stream_for_seeking_.second
519 ? fallback_stream_for_seeking_.first
520 : preferred_stream_for_seeking_.first;
511 DCHECK_NE(stream_index, -1); 521 DCHECK_NE(stream_index, -1);
512 522
513 const AVStream* seeking_stream = 523 const AVStream* seeking_stream =
514 glue_->format_context()->streams[stream_index]; 524 glue_->format_context()->streams[stream_index];
515 525
516 pending_seek_ = true; 526 pending_seek_ = true;
517 base::PostTaskAndReplyWithResult( 527 base::PostTaskAndReplyWithResult(
518 blocking_thread_.message_loop_proxy().get(), 528 blocking_thread_.message_loop_proxy().get(),
519 FROM_HERE, 529 FROM_HERE,
520 base::Bind(&av_seek_frame, 530 base::Bind(&av_seek_frame,
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
673 return; 683 return;
674 } 684 }
675 685
676 // Create demuxer stream entries for each possible AVStream. Each stream 686 // Create demuxer stream entries for each possible AVStream. Each stream
677 // is examined to determine if it is supported or not (is the codec enabled 687 // is examined to determine if it is supported or not (is the codec enabled
678 // for it in this release?). Unsupported streams are skipped, allowing for 688 // for it in this release?). Unsupported streams are skipped, allowing for
679 // partial playback. At least one audio or video stream must be playable. 689 // partial playback. At least one audio or video stream must be playable.
680 AVFormatContext* format_context = glue_->format_context(); 690 AVFormatContext* format_context = glue_->format_context();
681 streams_.resize(format_context->nb_streams); 691 streams_.resize(format_context->nb_streams);
682 692
693 // FFmpeg doesn't guarantee packets will be in timestamp order across streams
DaleCurtis 2014/06/27 21:10:33 If you decide we should keep this, I can refactor
694 // in an ogg container after a seek. Internally it only considers the file
695 // position when demuxing. It's an open question whether FFmpeg should fix
696 // this: http://lists.ffmpeg.org/pipermail/ffmpeg-devel/2014-June/159212.html
697 //
698 // As a workaround to ensure playback starts correctly, use the position of
699 // packets demuxed during avformat_find_stream_info() to adjust the seek info.
700 int first_ogg_stream = -1;
701 int64_t first_ogg_packet_pos = std::numeric_limits<int64_t>::max();
702
683 // Estimate the start time for each stream by looking through the packets 703 // Estimate the start time for each stream by looking through the packets
684 // buffered during avformat_find_stream_info(). These values will be 704 // buffered during avformat_find_stream_info(). These values will be
685 // considered later when determining the actual stream start time. 705 // considered later when determining the actual stream start time.
686 // 706 //
687 // These packets haven't been completely processed yet, so only look through 707 // These packets haven't been completely processed yet, so only look through
688 // these values if the AVFormatContext has a valid start time. 708 // these values if the AVFormatContext has a valid start time.
689 // 709 //
690 // If no estimate is found, the stream entry will be kInfiniteDuration(). 710 // If no estimate is found, the stream entry will be kInfiniteDuration().
691 std::vector<base::TimeDelta> start_time_estimates(format_context->nb_streams, 711 std::vector<base::TimeDelta> start_time_estimates(format_context->nb_streams,
692 kInfiniteDuration()); 712 kInfiniteDuration());
693 if (format_context->packet_buffer && 713 if (format_context->packet_buffer &&
694 format_context->start_time != static_cast<int64>(AV_NOPTS_VALUE)) { 714 format_context->start_time != static_cast<int64>(AV_NOPTS_VALUE)) {
695 struct AVPacketList* packet_buffer = format_context->packet_buffer; 715 struct AVPacketList* packet_buffer = format_context->packet_buffer;
696 while (packet_buffer != format_context->packet_buffer_end) { 716 while (packet_buffer != format_context->packet_buffer_end) {
697 DCHECK_LT(static_cast<size_t>(packet_buffer->pkt.stream_index), 717 DCHECK_LT(static_cast<size_t>(packet_buffer->pkt.stream_index),
698 start_time_estimates.size()); 718 start_time_estimates.size());
699 const AVStream* stream = 719 const AVStream* stream =
700 format_context->streams[packet_buffer->pkt.stream_index]; 720 format_context->streams[packet_buffer->pkt.stream_index];
701 if (packet_buffer->pkt.pts != static_cast<int64>(AV_NOPTS_VALUE)) { 721 if (packet_buffer->pkt.pts != static_cast<int64>(AV_NOPTS_VALUE)) {
702 const base::TimeDelta packet_pts = 722 const base::TimeDelta packet_pts =
703 ConvertFromTimeBase(stream->time_base, packet_buffer->pkt.pts); 723 ConvertFromTimeBase(stream->time_base, packet_buffer->pkt.pts);
704 if (packet_pts < start_time_estimates[stream->index]) 724 if (packet_pts < start_time_estimates[stream->index])
705 start_time_estimates[stream->index] = packet_pts; 725 start_time_estimates[stream->index] = packet_pts;
706 } 726 }
727 if (packet_buffer->pkt.pos != -1 &&
728 packet_buffer->pkt.pos < first_ogg_packet_pos) {
729 first_ogg_stream = stream->index;
730 first_ogg_packet_pos = packet_buffer->pkt.pos;
731 }
707 packet_buffer = packet_buffer->next; 732 packet_buffer = packet_buffer->next;
708 } 733 }
709 } 734 }
710 735
711 AVStream* audio_stream = NULL; 736 AVStream* audio_stream = NULL;
712 AudioDecoderConfig audio_config; 737 AudioDecoderConfig audio_config;
713 738
714 AVStream* video_stream = NULL; 739 AVStream* video_stream = NULL;
715 VideoDecoderConfig video_config; 740 VideoDecoderConfig video_config;
716 741
717 // If available, |start_time_| will be set to the lowest stream start time. 742 // If available, |start_time_| will be set to the lowest stream start time.
718 start_time_ = kInfiniteDuration(); 743 start_time_ = kInfiniteDuration();
719 744
720 base::TimeDelta max_duration; 745 base::TimeDelta max_duration;
721 for (size_t i = 0; i < format_context->nb_streams; ++i) { 746 for (size_t i = 0; i < format_context->nb_streams; ++i) {
722 AVStream* stream = format_context->streams[i]; 747 AVStream* stream = format_context->streams[i];
723 const AVCodecContext* codec_context = stream->codec; 748 const AVCodecContext* codec_context = stream->codec;
724 const AVMediaType codec_type = codec_context->codec_type; 749 const AVMediaType codec_type = codec_context->codec_type;
725 bool discard_negative_timestamps = false;
726 750
727 if (codec_type == AVMEDIA_TYPE_AUDIO) { 751 if (codec_type == AVMEDIA_TYPE_AUDIO) {
728 if (audio_stream) 752 if (audio_stream)
729 continue; 753 continue;
730 754
731 // Log the codec detected, whether it is supported or not. 755 // Log the codec detected, whether it is supported or not.
732 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedAudioCodec", 756 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedAudioCodec",
733 codec_context->codec_id); 757 codec_context->codec_id);
734 // Ensure the codec is supported. IsValidConfig() also checks that the 758 // Ensure the codec is supported. IsValidConfig() also checks that the
735 // channel layout and sample format are valid. 759 // channel layout and sample format are valid.
736 AVStreamToAudioDecoderConfig(stream, &audio_config, false); 760 AVStreamToAudioDecoderConfig(stream, &audio_config, false);
737 if (!audio_config.IsValidConfig()) 761 if (!audio_config.IsValidConfig())
738 continue; 762 continue;
739 audio_stream = stream; 763 audio_stream = stream;
740
741 // Enable post-decode frame dropping for packets with negative timestamps
742 // as outlined in section A.2 in the Ogg Vorbis spec:
743 // http://xiph.org/vorbis/doc/Vorbis_I_spec.html
744 discard_negative_timestamps =
745 audio_config.codec() == kCodecVorbis &&
746 strcmp(glue_->format_context()->iformat->name, "ogg") == 0;
747 } else if (codec_type == AVMEDIA_TYPE_VIDEO) { 764 } else if (codec_type == AVMEDIA_TYPE_VIDEO) {
748 if (video_stream) 765 if (video_stream)
749 continue; 766 continue;
750 767
751 // Log the codec detected, whether it is supported or not. 768 // Log the codec detected, whether it is supported or not.
752 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedVideoCodec", 769 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedVideoCodec",
753 codec_context->codec_id); 770 codec_context->codec_id);
754 // Ensure the codec is supported. IsValidConfig() also checks that the 771 // Ensure the codec is supported. IsValidConfig() also checks that the
755 // frame size and visible size are valid. 772 // frame size and visible size are valid.
756 AVStreamToVideoDecoderConfig(stream, &video_config, false); 773 AVStreamToVideoDecoderConfig(stream, &video_config, false);
757 774
758 if (!video_config.IsValidConfig()) 775 if (!video_config.IsValidConfig())
759 continue; 776 continue;
760 video_stream = stream; 777 video_stream = stream;
761 } else if (codec_type == AVMEDIA_TYPE_SUBTITLE) { 778 } else if (codec_type == AVMEDIA_TYPE_SUBTITLE) {
762 if (codec_context->codec_id != AV_CODEC_ID_WEBVTT || !text_enabled_) { 779 if (codec_context->codec_id != AV_CODEC_ID_WEBVTT || !text_enabled_) {
763 continue; 780 continue;
764 } 781 }
765 } else { 782 } else {
766 continue; 783 continue;
767 } 784 }
768 785
769 streams_[i] = 786 streams_[i] = new FFmpegDemuxerStream(this, stream);
770 new FFmpegDemuxerStream(this, stream, discard_negative_timestamps);
771 max_duration = std::max(max_duration, streams_[i]->duration()); 787 max_duration = std::max(max_duration, streams_[i]->duration());
772 788
773 const base::TimeDelta start_time = 789 const base::TimeDelta start_time =
774 ExtractStartTime(stream, start_time_estimates[i]); 790 ExtractStartTime(stream, start_time_estimates[i]);
775 if (start_time == kNoTimestamp()) 791 const bool has_start_time = start_time != kNoTimestamp();
792
793 // Always prefer the video stream for seeking. If none exists, we'll swap
794 // the fallback stream with the preferred stream below.
795 if (codec_type == AVMEDIA_TYPE_VIDEO) {
796 preferred_stream_for_seeking_ =
797 StreamSeekInfo(i, has_start_time ? start_time : base::TimeDelta());
798 }
799
800 if (!has_start_time)
776 continue; 801 continue;
777 802
778 if (start_time < start_time_) { 803 if (start_time < start_time_) {
779 start_time_ = start_time; 804 start_time_ = start_time;
780 805
781 // Choose the stream with the lowest starting time as the fallback stream 806 // Choose the stream with the lowest starting time as the fallback stream
782 // for seeking. Video should always be preferred. 807 // for seeking. Video should always be preferred.
783 fallback_stream_for_seeking_ = std::make_pair(i, start_time); 808 fallback_stream_for_seeking_ = StreamSeekInfo(i, start_time);
784 } 809 }
785
786 // Always prefer the video stream for seeking. If none exists, we'll swap
787 // the fallback stream with the preferred stream below.
788 if (codec_type == AVMEDIA_TYPE_VIDEO)
789 preferred_stream_for_seeking_ = std::make_pair(i, start_time);
790 } 810 }
791 811
792 if (!audio_stream && !video_stream) { 812 if (!audio_stream && !video_stream) {
793 status_cb.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); 813 status_cb.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
794 return; 814 return;
795 } 815 }
796 816
797 if (text_enabled_) 817 if (text_enabled_)
798 AddTextStreams(); 818 AddTextStreams();
799 819
800 if (format_context->duration != static_cast<int64_t>(AV_NOPTS_VALUE)) { 820 if (format_context->duration != static_cast<int64_t>(AV_NOPTS_VALUE)) {
801 // If there is a duration value in the container use that to find the 821 // If there is a duration value in the container use that to find the
802 // maximum between it and the duration from A/V streams. 822 // maximum between it and the duration from A/V streams.
803 const AVRational av_time_base = {1, AV_TIME_BASE}; 823 const AVRational av_time_base = {1, AV_TIME_BASE};
804 max_duration = 824 max_duration =
805 std::max(max_duration, 825 std::max(max_duration,
806 ConvertFromTimeBase(av_time_base, format_context->duration)); 826 ConvertFromTimeBase(av_time_base, format_context->duration));
807 } else { 827 } else {
808 // The duration is unknown, in which case this is likely a live stream. 828 // The duration is unknown, in which case this is likely a live stream.
809 max_duration = kInfiniteDuration(); 829 max_duration = kInfiniteDuration();
810 } 830 }
811 831
832 // Ogg has some peculiarities around negative timestamps, so use this flag to
833 // setup the FFmpegDemuxerStreams appropriately.
834 //
835 // Post-decode frame dropping for packets with negative timestamps is outlined
836 // in section A.2 in the Ogg Vorbis spec:
837 // http://xiph.org/vorbis/doc/Vorbis_I_spec.html
838 if (strcmp(format_context->iformat->name, "ogg") == 0 && audio_stream &&
839 audio_stream->codec->codec_id == AV_CODEC_ID_VORBIS) {
840 for (size_t i = 0; i < streams_.size(); ++i) {
841 if (streams_[i])
842 streams_[i]->enable_negative_timestamp_fixups_for_ogg();
843 }
844
845 // Fixup the seeking information to avoid selecting the audio stream unless
846 // it has a lower file position. See notes on |first_ogg_stream|.
847 if (first_ogg_stream != audio_stream->index &&
848 fallback_stream_for_seeking_.first == audio_stream->index &&
849 fallback_stream_for_seeking_.second < base::TimeDelta()) {
850 fallback_stream_for_seeking_.second = base::TimeDelta();
851 }
852 }
853
812 // If no start time could be determined, default to zero and prefer the video 854 // If no start time could be determined, default to zero and prefer the video
813 // stream over the audio stream for seeking. E.g., The WAV demuxer does not 855 // stream over the audio stream for seeking. E.g., The WAV demuxer does not
814 // put timestamps on its frames. 856 // put timestamps on its frames.
815 if (start_time_ == kInfiniteDuration()) { 857 if (start_time_ == kInfiniteDuration()) {
816 start_time_ = base::TimeDelta(); 858 start_time_ = base::TimeDelta();
817 preferred_stream_for_seeking_ = std::make_pair( 859 preferred_stream_for_seeking_ = StreamSeekInfo(
818 video_stream ? video_stream->index : audio_stream->index, start_time_); 860 video_stream ? video_stream->index : audio_stream->index, start_time_);
819 } else if (!video_stream) { 861 } else if (!video_stream) {
820 // If no video stream exists, use the audio or text stream found above. 862 // If no video stream exists, use the audio or text stream found above.
821 preferred_stream_for_seeking_ = fallback_stream_for_seeking_; 863 preferred_stream_for_seeking_ = fallback_stream_for_seeking_;
822 } 864 }
823 865
824 // MPEG-4 B-frames cause grief for a simple container like AVI. Enable PTS 866 // MPEG-4 B-frames cause grief for a simple container like AVI. Enable PTS
825 // generation so we always get timestamps, see http://crbug.com/169570 867 // generation so we always get timestamps, see http://crbug.com/169570
826 if (strcmp(format_context->iformat->name, "avi") == 0) 868 if (strcmp(format_context->iformat->name, "avi") == 0)
827 format_context->flags |= AVFMT_FLAG_GENPTS; 869 format_context->flags |= AVFMT_FLAG_GENPTS;
(...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after
1134 } 1176 }
1135 for (size_t i = 0; i < buffered.size(); ++i) 1177 for (size_t i = 0; i < buffered.size(); ++i)
1136 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i)); 1178 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i));
1137 } 1179 }
1138 1180
1139 void FFmpegDemuxer::OnDataSourceError() { 1181 void FFmpegDemuxer::OnDataSourceError() {
1140 host_->OnDemuxerError(PIPELINE_ERROR_READ); 1182 host_->OnDemuxerError(PIPELINE_ERROR_READ);
1141 } 1183 }
1142 1184
1143 } // namespace media 1185 } // 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