OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |