Chromium Code Reviews| 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 <memory> | 8 #include <memory> |
| 9 #include <set> | 9 #include <set> |
| 10 #include <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/base64.h" | 12 #include "base/base64.h" |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/callback_helpers.h" | 14 #include "base/callback_helpers.h" |
| 15 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
| 17 #include "base/metrics/histogram_macros.h" | 17 #include "base/metrics/histogram_macros.h" |
| 18 #include "base/metrics/sparse_histogram.h" | 18 #include "base/metrics/sparse_histogram.h" |
| 19 #include "base/single_thread_task_runner.h" | 19 #include "base/single_thread_task_runner.h" |
| 20 #include "base/strings/string_number_conversions.h" | 20 #include "base/strings/string_number_conversions.h" |
| 21 #include "base/strings/string_util.h" | 21 #include "base/strings/string_util.h" |
| 22 #include "base/strings/stringprintf.h" | 22 #include "base/strings/stringprintf.h" |
| 23 #include "base/sys_byteorder.h" | 23 #include "base/sys_byteorder.h" |
| 24 #include "base/task_runner_util.h" | 24 #include "base/task_runner_util.h" |
| 25 #include "base/task_scheduler/post_task.h" | |
| 26 #include "base/threading/sequenced_worker_pool.h" | |
| 25 #include "base/threading/thread_task_runner_handle.h" | 27 #include "base/threading/thread_task_runner_handle.h" |
| 26 #include "base/time/time.h" | 28 #include "base/time/time.h" |
| 27 #include "media/audio/sample_rates.h" | 29 #include "media/audio/sample_rates.h" |
| 28 #include "media/base/bind_to_current_loop.h" | 30 #include "media/base/bind_to_current_loop.h" |
| 29 #include "media/base/decrypt_config.h" | 31 #include "media/base/decrypt_config.h" |
| 30 #include "media/base/limits.h" | 32 #include "media/base/limits.h" |
| 31 #include "media/base/media_log.h" | 33 #include "media/base/media_log.h" |
| 32 #include "media/base/media_tracks.h" | 34 #include "media/base/media_tracks.h" |
| 33 #include "media/base/timestamp_constants.h" | 35 #include "media/base/timestamp_constants.h" |
| 34 #include "media/base/video_codecs.h" | 36 #include "media/base/video_codecs.h" |
| (...skipping 803 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 838 // FFmpegDemuxer | 840 // FFmpegDemuxer |
| 839 // | 841 // |
| 840 FFmpegDemuxer::FFmpegDemuxer( | 842 FFmpegDemuxer::FFmpegDemuxer( |
| 841 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 843 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| 842 DataSource* data_source, | 844 DataSource* data_source, |
| 843 const EncryptedMediaInitDataCB& encrypted_media_init_data_cb, | 845 const EncryptedMediaInitDataCB& encrypted_media_init_data_cb, |
| 844 const MediaTracksUpdatedCB& media_tracks_updated_cb, | 846 const MediaTracksUpdatedCB& media_tracks_updated_cb, |
| 845 const scoped_refptr<MediaLog>& media_log) | 847 const scoped_refptr<MediaLog>& media_log) |
| 846 : host_(NULL), | 848 : host_(NULL), |
| 847 task_runner_(task_runner), | 849 task_runner_(task_runner), |
| 848 blocking_thread_("FFmpegDemuxer"), | 850 // FFmpeg has no asynchronous API, so we use base::WaitableEvents inside |
| 851 // the BlockingUrlProtocol to handle hops to the render thread for network | |
| 852 // reads and seeks. | |
| 853 blocking_task_runner_(base::CreateSequencedTaskRunnerWithTraits( | |
| 854 base::TaskTraits().MayBlock().WithBaseSyncPrimitives().WithPriority( | |
| 855 base::TaskPriority::USER_BLOCKING))), | |
| 856 stopped_(false), | |
| 849 pending_read_(false), | 857 pending_read_(false), |
| 850 data_source_(data_source), | 858 data_source_(data_source), |
| 851 media_log_(media_log), | 859 media_log_(media_log), |
| 852 bitrate_(0), | 860 bitrate_(0), |
| 853 start_time_(kNoTimestamp), | 861 start_time_(kNoTimestamp), |
| 854 text_enabled_(false), | 862 text_enabled_(false), |
| 855 duration_known_(false), | 863 duration_known_(false), |
| 856 encrypted_media_init_data_cb_(encrypted_media_init_data_cb), | 864 encrypted_media_init_data_cb_(encrypted_media_init_data_cb), |
| 857 media_tracks_updated_cb_(media_tracks_updated_cb), | 865 media_tracks_updated_cb_(media_tracks_updated_cb), |
| 858 cancel_pending_seek_factory_(this), | 866 cancel_pending_seek_factory_(this), |
| 859 weak_factory_(this) { | 867 weak_factory_(this) { |
| 860 DCHECK(task_runner_.get()); | 868 DCHECK(task_runner_.get()); |
| 861 DCHECK(data_source_); | 869 DCHECK(data_source_); |
| 862 DCHECK(!media_tracks_updated_cb_.is_null()); | 870 DCHECK(!media_tracks_updated_cb_.is_null()); |
| 863 } | 871 } |
| 864 | 872 |
| 865 FFmpegDemuxer::~FFmpegDemuxer() { | 873 FFmpegDemuxer::~FFmpegDemuxer() { |
| 866 // NOTE: This class is not destroyed on |task_runner|, so we must ensure that | 874 // NOTE: This class is not destroyed on |task_runner|, so we must ensure that |
| 867 // there are no outstanding WeakPtrs by the time we reach here. | 875 // there are no outstanding WeakPtrs by the time we reach here. |
| 868 DCHECK(!weak_factory_.HasWeakPtrs()); | 876 DCHECK(!weak_factory_.HasWeakPtrs()); |
| 877 | |
| 878 // There may be outstanding tasks in the blocking pool which are trying to use | |
| 879 // these members, so release them in sequence with any outstanding calls. The | |
| 880 // earlier call to Abort() on |data_source_| prevents further access to it. | |
| 881 blocking_task_runner_->DeleteSoon(FROM_HERE, url_protocol_.release()); | |
| 882 blocking_task_runner_->DeleteSoon(FROM_HERE, glue_.release()); | |
| 869 } | 883 } |
| 870 | 884 |
| 871 std::string FFmpegDemuxer::GetDisplayName() const { | 885 std::string FFmpegDemuxer::GetDisplayName() const { |
| 872 return "FFmpegDemuxer"; | 886 return "FFmpegDemuxer"; |
| 873 } | 887 } |
| 874 | 888 |
| 875 void FFmpegDemuxer::Initialize(DemuxerHost* host, | 889 void FFmpegDemuxer::Initialize(DemuxerHost* host, |
| 876 const PipelineStatusCB& status_cb, | 890 const PipelineStatusCB& status_cb, |
| 877 bool enable_text_tracks) { | 891 bool enable_text_tracks) { |
| 878 DCHECK(task_runner_->BelongsToCurrentThread()); | 892 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 879 host_ = host; | 893 host_ = host; |
| 880 text_enabled_ = enable_text_tracks; | 894 text_enabled_ = enable_text_tracks; |
| 881 weak_this_ = cancel_pending_seek_factory_.GetWeakPtr(); | 895 weak_this_ = cancel_pending_seek_factory_.GetWeakPtr(); |
| 882 | 896 |
| 897 // Give a WeakPtr to BlockingUrlProtocol since we'll need to release it on the | |
| 898 // blocking thread pool. | |
| 883 url_protocol_.reset(new BlockingUrlProtocol( | 899 url_protocol_.reset(new BlockingUrlProtocol( |
| 884 data_source_, | 900 data_source_, BindToCurrentLoop(base::Bind( |
| 885 BindToCurrentLoop(base::Bind(&FFmpegDemuxer::OnDataSourceError, | 901 &FFmpegDemuxer::OnDataSourceError, weak_this_)))); |
|
xhwang
2017/03/02 22:05:01
We have mixed use of weak_this_ and weak_factory_.
DaleCurtis
2017/03/02 22:48:53
weak_this_ is bound to a factory which should only
xhwang
2017/03/02 23:07:13
Ah, that's tricky and I didn't even notice it. A f
| |
| 886 base::Unretained(this))))); | |
| 887 glue_.reset(new FFmpegGlue(url_protocol_.get())); | 902 glue_.reset(new FFmpegGlue(url_protocol_.get())); |
| 888 AVFormatContext* format_context = glue_->format_context(); | 903 AVFormatContext* format_context = glue_->format_context(); |
| 889 | 904 |
| 890 // Disable ID3v1 tag reading to avoid costly seeks to end of file for data we | 905 // Disable ID3v1 tag reading to avoid costly seeks to end of file for data we |
| 891 // don't use. FFmpeg will only read ID3v1 tags if no other metadata is | 906 // don't use. FFmpeg will only read ID3v1 tags if no other metadata is |
| 892 // available, so add a metadata entry to ensure some is always present. | 907 // available, so add a metadata entry to ensure some is always present. |
| 893 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0); | 908 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0); |
| 894 | 909 |
| 895 // Ensure ffmpeg doesn't give up too early while looking for stream params; | 910 // Ensure ffmpeg doesn't give up too early while looking for stream params; |
| 896 // this does not increase the amount of data downloaded. The default value | 911 // this does not increase the amount of data downloaded. The default value |
| 897 // is 5 AV_TIME_BASE units (1 second each), which prevents some oddly muxed | 912 // is 5 AV_TIME_BASE units (1 second each), which prevents some oddly muxed |
| 898 // streams from being detected properly; this value was chosen arbitrarily. | 913 // streams from being detected properly; this value was chosen arbitrarily. |
| 899 format_context->max_analyze_duration = 60 * AV_TIME_BASE; | 914 format_context->max_analyze_duration = 60 * AV_TIME_BASE; |
| 900 | 915 |
| 901 // Open the AVFormatContext using our glue layer. | 916 // Open the AVFormatContext using our glue layer. |
| 902 CHECK(blocking_thread_.Start()); | |
| 903 base::PostTaskAndReplyWithResult( | 917 base::PostTaskAndReplyWithResult( |
| 904 blocking_thread_.task_runner().get(), FROM_HERE, | 918 blocking_task_runner_.get(), FROM_HERE, |
| 905 base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())), | 919 base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())), |
| 906 base::Bind(&FFmpegDemuxer::OnOpenContextDone, weak_factory_.GetWeakPtr(), | 920 base::Bind(&FFmpegDemuxer::OnOpenContextDone, weak_factory_.GetWeakPtr(), |
| 907 status_cb)); | 921 status_cb)); |
| 908 } | 922 } |
| 909 | 923 |
| 910 void FFmpegDemuxer::AbortPendingReads() { | 924 void FFmpegDemuxer::AbortPendingReads() { |
| 911 DCHECK(task_runner_->BelongsToCurrentThread()); | 925 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 912 | 926 |
| 913 // If Stop() has been called, then drop this call. | 927 // If Stop() has been called, then drop this call. |
| 914 if (!blocking_thread_.IsRunning()) | 928 if (stopped_) |
| 915 return; | 929 return; |
| 916 | 930 |
| 917 // This should only be called after the demuxer has been initialized. | 931 // This should only be called after the demuxer has been initialized. |
| 918 DCHECK_GT(streams_.size(), 0u); | 932 DCHECK_GT(streams_.size(), 0u); |
| 919 | 933 |
| 920 // Abort all outstanding reads. | 934 // Abort all outstanding reads. |
| 921 for (const auto& stream : streams_) { | 935 for (const auto& stream : streams_) { |
| 922 if (stream) | 936 if (stream) |
| 923 stream->Abort(); | 937 stream->Abort(); |
| 924 } | 938 } |
| 925 | 939 |
| 926 // It's important to invalidate read/seek completion callbacks to avoid any | 940 // It's important to invalidate read/seek completion callbacks to avoid any |
| 927 // errors that occur because of the data source abort. | 941 // errors that occur because of the data source abort. |
| 928 weak_factory_.InvalidateWeakPtrs(); | 942 weak_factory_.InvalidateWeakPtrs(); |
| 929 data_source_->Abort(); | 943 data_source_->Abort(); |
| 930 | 944 |
| 931 // Aborting the read may cause EOF to be marked, undo this. | 945 // Aborting the read may cause EOF to be marked, undo this. |
| 932 blocking_thread_.task_runner()->PostTask( | 946 blocking_task_runner_->PostTask( |
| 933 FROM_HERE, base::Bind(&UnmarkEndOfStream, glue_->format_context())); | 947 FROM_HERE, base::Bind(&UnmarkEndOfStream, glue_->format_context())); |
| 934 pending_read_ = false; | 948 pending_read_ = false; |
| 935 | 949 |
| 936 // TODO(dalecurtis): We probably should report PIPELINE_ERROR_ABORT here | 950 // TODO(dalecurtis): We probably should report PIPELINE_ERROR_ABORT here |
| 937 // instead to avoid any preroll work that may be started upon return, but | 951 // instead to avoid any preroll work that may be started upon return, but |
| 938 // currently the PipelineImpl does not know how to handle this. | 952 // currently the PipelineImpl does not know how to handle this. |
| 939 if (!pending_seek_cb_.is_null()) | 953 if (!pending_seek_cb_.is_null()) |
| 940 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_OK); | 954 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_OK); |
| 941 } | 955 } |
| 942 | 956 |
| 943 void FFmpegDemuxer::Stop() { | 957 void FFmpegDemuxer::Stop() { |
| 944 DCHECK(task_runner_->BelongsToCurrentThread()); | 958 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 945 | 959 |
| 946 // The order of Stop() and Abort() is important here. If Abort() is called | 960 // The order of Stop() and Abort() is important here. If Abort() is called |
| 947 // first, control may pass into FFmpeg where it can destruct buffers that are | 961 // first, control may pass into FFmpeg where it can destruct buffers that are |
| 948 // in the process of being fulfilled by the DataSource. | 962 // in the process of being fulfilled by the DataSource. |
| 949 data_source_->Stop(); | 963 data_source_->Stop(); |
| 950 url_protocol_->Abort(); | 964 url_protocol_->Abort(); |
| 951 | 965 |
| 952 // This will block until all tasks complete. Note that after this returns it's | |
| 953 // possible for reply tasks (e.g., OnReadFrameDone()) to be queued on this | |
| 954 // thread. Each of the reply task methods must check whether we've stopped the | |
| 955 // thread and drop their results on the floor. | |
| 956 blocking_thread_.Stop(); | |
| 957 | |
| 958 for (const auto& stream : streams_) { | 966 for (const auto& stream : streams_) { |
| 959 if (stream) | 967 if (stream) |
| 960 stream->Stop(); | 968 stream->Stop(); |
| 961 } | 969 } |
| 962 | 970 |
| 963 data_source_ = NULL; | 971 data_source_ = NULL; |
| 964 | 972 |
| 965 // Invalidate WeakPtrs on |task_runner_|, destruction may happen on another | 973 // Invalidate WeakPtrs on |task_runner_|, destruction may happen on another |
| 966 // thread. | 974 // thread. We don't need to wait for any outstanding tasks since they will all |
| 975 // fail to return after invalidating WeakPtrs. | |
| 976 stopped_ = true; | |
| 967 weak_factory_.InvalidateWeakPtrs(); | 977 weak_factory_.InvalidateWeakPtrs(); |
| 968 cancel_pending_seek_factory_.InvalidateWeakPtrs(); | 978 cancel_pending_seek_factory_.InvalidateWeakPtrs(); |
| 969 } | 979 } |
| 970 | 980 |
| 971 void FFmpegDemuxer::StartWaitingForSeek(base::TimeDelta seek_time) {} | 981 void FFmpegDemuxer::StartWaitingForSeek(base::TimeDelta seek_time) {} |
| 972 | 982 |
| 973 void FFmpegDemuxer::CancelPendingSeek(base::TimeDelta seek_time) { | 983 void FFmpegDemuxer::CancelPendingSeek(base::TimeDelta seek_time) { |
| 974 if (task_runner_->BelongsToCurrentThread()) { | 984 if (task_runner_->BelongsToCurrentThread()) { |
| 975 AbortPendingReads(); | 985 AbortPendingReads(); |
| 976 } else { | 986 } else { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1015 // be demuxed. It's an open question whether FFmpeg should fix this: | 1025 // be demuxed. It's an open question whether FFmpeg should fix this: |
| 1016 // http://lists.ffmpeg.org/pipermail/ffmpeg-devel/2014-June/159212.html | 1026 // http://lists.ffmpeg.org/pipermail/ffmpeg-devel/2014-June/159212.html |
| 1017 // Tracked by http://crbug.com/387996. | 1027 // Tracked by http://crbug.com/387996. |
| 1018 FFmpegDemuxerStream* demux_stream = FindPreferredStreamForSeeking(seek_time); | 1028 FFmpegDemuxerStream* demux_stream = FindPreferredStreamForSeeking(seek_time); |
| 1019 DCHECK(demux_stream); | 1029 DCHECK(demux_stream); |
| 1020 const AVStream* seeking_stream = demux_stream->av_stream(); | 1030 const AVStream* seeking_stream = demux_stream->av_stream(); |
| 1021 DCHECK(seeking_stream); | 1031 DCHECK(seeking_stream); |
| 1022 | 1032 |
| 1023 pending_seek_cb_ = cb; | 1033 pending_seek_cb_ = cb; |
| 1024 base::PostTaskAndReplyWithResult( | 1034 base::PostTaskAndReplyWithResult( |
| 1025 blocking_thread_.task_runner().get(), FROM_HERE, | 1035 blocking_task_runner_.get(), FROM_HERE, |
| 1026 base::Bind(&av_seek_frame, glue_->format_context(), seeking_stream->index, | 1036 base::Bind(&av_seek_frame, glue_->format_context(), seeking_stream->index, |
| 1027 ConvertToTimeBase(seeking_stream->time_base, seek_time), | 1037 ConvertToTimeBase(seeking_stream->time_base, seek_time), |
| 1028 // Always seek to a timestamp <= to the desired timestamp. | 1038 // Always seek to a timestamp <= to the desired timestamp. |
| 1029 AVSEEK_FLAG_BACKWARD), | 1039 AVSEEK_FLAG_BACKWARD), |
| 1030 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, weak_factory_.GetWeakPtr())); | 1040 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, weak_factory_.GetWeakPtr())); |
| 1031 } | 1041 } |
| 1032 | 1042 |
| 1033 base::Time FFmpegDemuxer::GetTimelineOffset() const { | 1043 base::Time FFmpegDemuxer::GetTimelineOffset() const { |
| 1034 return timeline_offset_; | 1044 return timeline_offset_; |
| 1035 } | 1045 } |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1160 // Do math in floating point as we'd overflow an int64_t if the filesize was | 1170 // Do math in floating point as we'd overflow an int64_t if the filesize was |
| 1161 // larger than ~1073GB. | 1171 // larger than ~1073GB. |
| 1162 double bytes = filesize_in_bytes; | 1172 double bytes = filesize_in_bytes; |
| 1163 double duration_us = duration.InMicroseconds(); | 1173 double duration_us = duration.InMicroseconds(); |
| 1164 return bytes * 8000000.0 / duration_us; | 1174 return bytes * 8000000.0 / duration_us; |
| 1165 } | 1175 } |
| 1166 | 1176 |
| 1167 void FFmpegDemuxer::OnOpenContextDone(const PipelineStatusCB& status_cb, | 1177 void FFmpegDemuxer::OnOpenContextDone(const PipelineStatusCB& status_cb, |
| 1168 bool result) { | 1178 bool result) { |
| 1169 DCHECK(task_runner_->BelongsToCurrentThread()); | 1179 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1170 if (!blocking_thread_.IsRunning()) { | 1180 if (stopped_) { |
| 1171 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; | 1181 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; |
| 1172 status_cb.Run(PIPELINE_ERROR_ABORT); | 1182 status_cb.Run(PIPELINE_ERROR_ABORT); |
| 1173 return; | 1183 return; |
| 1174 } | 1184 } |
| 1175 | 1185 |
| 1176 if (!result) { | 1186 if (!result) { |
| 1177 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": open context failed"; | 1187 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": open context failed"; |
| 1178 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN); | 1188 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN); |
| 1179 return; | 1189 return; |
| 1180 } | 1190 } |
| 1181 | 1191 |
| 1182 // Fully initialize AVFormatContext by parsing the stream a little. | 1192 // Fully initialize AVFormatContext by parsing the stream a little. |
| 1183 base::PostTaskAndReplyWithResult( | 1193 base::PostTaskAndReplyWithResult( |
| 1184 blocking_thread_.task_runner().get(), | 1194 blocking_task_runner_.get(), FROM_HERE, |
| 1185 FROM_HERE, | 1195 base::Bind(&avformat_find_stream_info, glue_->format_context(), |
| 1186 base::Bind(&avformat_find_stream_info, | |
| 1187 glue_->format_context(), | |
| 1188 static_cast<AVDictionary**>(NULL)), | 1196 static_cast<AVDictionary**>(NULL)), |
| 1189 base::Bind(&FFmpegDemuxer::OnFindStreamInfoDone, | 1197 base::Bind(&FFmpegDemuxer::OnFindStreamInfoDone, |
| 1190 weak_factory_.GetWeakPtr(), | 1198 weak_factory_.GetWeakPtr(), status_cb)); |
| 1191 status_cb)); | |
| 1192 } | 1199 } |
| 1193 | 1200 |
| 1194 void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, | 1201 void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, |
| 1195 int result) { | 1202 int result) { |
| 1196 DCHECK(task_runner_->BelongsToCurrentThread()); | 1203 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1197 if (!blocking_thread_.IsRunning() || !data_source_) { | 1204 if (stopped_ || !data_source_) { |
| 1198 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; | 1205 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; |
| 1199 status_cb.Run(PIPELINE_ERROR_ABORT); | 1206 status_cb.Run(PIPELINE_ERROR_ABORT); |
| 1200 return; | 1207 return; |
| 1201 } | 1208 } |
| 1202 | 1209 |
| 1203 if (result < 0) { | 1210 if (result < 0) { |
| 1204 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() | 1211 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() |
| 1205 << ": find stream info failed"; | 1212 << ": find stream info failed"; |
| 1206 status_cb.Run(DEMUXER_ERROR_COULD_NOT_PARSE); | 1213 status_cb.Run(DEMUXER_ERROR_COULD_NOT_PARSE); |
| 1207 return; | 1214 return; |
| (...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1607 } | 1614 } |
| 1608 | 1615 |
| 1609 NOTREACHED(); | 1616 NOTREACHED(); |
| 1610 return nullptr; | 1617 return nullptr; |
| 1611 } | 1618 } |
| 1612 | 1619 |
| 1613 void FFmpegDemuxer::OnSeekFrameDone(int result) { | 1620 void FFmpegDemuxer::OnSeekFrameDone(int result) { |
| 1614 DCHECK(task_runner_->BelongsToCurrentThread()); | 1621 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1615 CHECK(!pending_seek_cb_.is_null()); | 1622 CHECK(!pending_seek_cb_.is_null()); |
| 1616 | 1623 |
| 1617 if (!blocking_thread_.IsRunning()) { | 1624 if (stopped_) { |
| 1618 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; | 1625 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; |
| 1619 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_ERROR_ABORT); | 1626 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_ERROR_ABORT); |
| 1620 return; | 1627 return; |
| 1621 } | 1628 } |
| 1622 | 1629 |
| 1623 if (result < 0) { | 1630 if (result < 0) { |
| 1624 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being | 1631 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being |
| 1625 // captured from stdout and contaminates testing. | 1632 // captured from stdout and contaminates testing. |
| 1626 // TODO(scherkus): Implement this properly and signal error (BUG=23447). | 1633 // TODO(scherkus): Implement this properly and signal error (BUG=23447). |
| 1627 VLOG(1) << "Not implemented"; | 1634 VLOG(1) << "Not implemented"; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1693 if (selected_stream) { | 1700 if (selected_stream) { |
| 1694 DVLOG(1) << __func__ << ": enabling stream " << selected_stream; | 1701 DVLOG(1) << __func__ << ": enabling stream " << selected_stream; |
| 1695 selected_stream->set_enabled(true, curr_time); | 1702 selected_stream->set_enabled(true, curr_time); |
| 1696 } | 1703 } |
| 1697 } | 1704 } |
| 1698 | 1705 |
| 1699 void FFmpegDemuxer::ReadFrameIfNeeded() { | 1706 void FFmpegDemuxer::ReadFrameIfNeeded() { |
| 1700 DCHECK(task_runner_->BelongsToCurrentThread()); | 1707 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1701 | 1708 |
| 1702 // Make sure we have work to do before reading. | 1709 // Make sure we have work to do before reading. |
| 1703 if (!blocking_thread_.IsRunning() || !StreamsHaveAvailableCapacity() || | 1710 if (stopped_ || !StreamsHaveAvailableCapacity() || pending_read_ || |
| 1704 pending_read_ || !pending_seek_cb_.is_null()) { | 1711 !pending_seek_cb_.is_null()) { |
| 1705 return; | 1712 return; |
| 1706 } | 1713 } |
| 1707 | 1714 |
| 1708 // Allocate and read an AVPacket from the media. Save |packet_ptr| since | 1715 // Allocate and read an AVPacket from the media. Save |packet_ptr| since |
| 1709 // evaluation order of packet.get() and base::Passed(&packet) is | 1716 // evaluation order of packet.get() and base::Passed(&packet) is |
| 1710 // undefined. | 1717 // undefined. |
| 1711 ScopedAVPacket packet(new AVPacket()); | 1718 ScopedAVPacket packet(new AVPacket()); |
| 1712 AVPacket* packet_ptr = packet.get(); | 1719 AVPacket* packet_ptr = packet.get(); |
| 1713 | 1720 |
| 1714 pending_read_ = true; | 1721 pending_read_ = true; |
| 1715 base::PostTaskAndReplyWithResult( | 1722 base::PostTaskAndReplyWithResult( |
| 1716 blocking_thread_.task_runner().get(), | 1723 blocking_task_runner_.get(), FROM_HERE, |
| 1717 FROM_HERE, | |
| 1718 base::Bind(&av_read_frame, glue_->format_context(), packet_ptr), | 1724 base::Bind(&av_read_frame, glue_->format_context(), packet_ptr), |
| 1719 base::Bind(&FFmpegDemuxer::OnReadFrameDone, | 1725 base::Bind(&FFmpegDemuxer::OnReadFrameDone, weak_factory_.GetWeakPtr(), |
| 1720 weak_factory_.GetWeakPtr(), | |
| 1721 base::Passed(&packet))); | 1726 base::Passed(&packet))); |
| 1722 } | 1727 } |
| 1723 | 1728 |
| 1724 void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) { | 1729 void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) { |
| 1725 DCHECK(task_runner_->BelongsToCurrentThread()); | 1730 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1726 DCHECK(pending_read_); | 1731 DCHECK(pending_read_); |
| 1727 pending_read_ = false; | 1732 pending_read_ = false; |
| 1728 | 1733 |
| 1729 if (!blocking_thread_.IsRunning() || !pending_seek_cb_.is_null()) | 1734 if (stopped_ || !pending_seek_cb_.is_null()) |
| 1730 return; | 1735 return; |
| 1731 | 1736 |
| 1732 // Consider the stream as ended if: | 1737 // Consider the stream as ended if: |
| 1733 // - either underlying ffmpeg returned an error | 1738 // - either underlying ffmpeg returned an error |
| 1734 // - or FFMpegDemuxer reached the maximum allowed memory usage. | 1739 // - or FFMpegDemuxer reached the maximum allowed memory usage. |
| 1735 if (result < 0 || IsMaxMemoryUsageReached()) { | 1740 if (result < 0 || IsMaxMemoryUsageReached()) { |
| 1736 DVLOG(1) << __func__ << " result=" << result | 1741 DVLOG(1) << __func__ << " result=" << result |
| 1737 << " IsMaxMemoryUsageReached=" << IsMaxMemoryUsageReached(); | 1742 << " IsMaxMemoryUsageReached=" << IsMaxMemoryUsageReached(); |
| 1738 // Update the duration based on the highest elapsed time across all streams. | 1743 // Update the duration based on the highest elapsed time across all streams. |
| 1739 base::TimeDelta max_duration; | 1744 base::TimeDelta max_duration; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1844 | 1849 |
| 1845 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { | 1850 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { |
| 1846 DCHECK(task_runner_->BelongsToCurrentThread()); | 1851 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1847 for (const auto& stream : streams_) { | 1852 for (const auto& stream : streams_) { |
| 1848 if (stream) | 1853 if (stream) |
| 1849 stream->SetLiveness(liveness); | 1854 stream->SetLiveness(liveness); |
| 1850 } | 1855 } |
| 1851 } | 1856 } |
| 1852 | 1857 |
| 1853 } // namespace media | 1858 } // namespace media |
| OLD | NEW |