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( | |
|
gab
2017/02/23 21:37:09
Trusting you and your reviewer on these since I'm
| |
| 855 base::TaskPriority::USER_VISIBLE))), | |
|
gab
2017/02/23 21:37:10
Is this used for live video/audio? i.e TaskPriorit
DaleCurtis
2017/02/23 23:07:06
It could be live audio video. The user may even wa
gab
2017/02/24 01:09:05
IMO "blocking UI from rendering" and "decoding a l
| |
| 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()); | |
|
gab
2017/02/23 21:37:10
Have you considered binding those tasks to WeakPtr
DaleCurtis
2017/02/23 23:07:06
Can't; these tasks are bound to static methods. We
| |
| 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()); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 892 // available, so add a metadata entry to ensure some is always present. | 906 // available, so add a metadata entry to ensure some is always present. |
| 893 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0); | 907 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0); |
| 894 | 908 |
| 895 // Ensure ffmpeg doesn't give up too early while looking for stream params; | 909 // 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 | 910 // 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 | 911 // 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. | 912 // streams from being detected properly; this value was chosen arbitrarily. |
| 899 format_context->max_analyze_duration = 60 * AV_TIME_BASE; | 913 format_context->max_analyze_duration = 60 * AV_TIME_BASE; |
| 900 | 914 |
| 901 // Open the AVFormatContext using our glue layer. | 915 // Open the AVFormatContext using our glue layer. |
| 902 CHECK(blocking_thread_.Start()); | |
| 903 base::PostTaskAndReplyWithResult( | 916 base::PostTaskAndReplyWithResult( |
| 904 blocking_thread_.task_runner().get(), FROM_HERE, | 917 blocking_task_runner_.get(), FROM_HERE, |
| 905 base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())), | 918 base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())), |
| 906 base::Bind(&FFmpegDemuxer::OnOpenContextDone, weak_factory_.GetWeakPtr(), | 919 base::Bind(&FFmpegDemuxer::OnOpenContextDone, weak_factory_.GetWeakPtr(), |
| 907 status_cb)); | 920 status_cb)); |
| 908 } | 921 } |
| 909 | 922 |
| 910 void FFmpegDemuxer::AbortPendingReads() { | 923 void FFmpegDemuxer::AbortPendingReads() { |
| 911 DCHECK(task_runner_->BelongsToCurrentThread()); | 924 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 912 | 925 |
| 913 // If Stop() has been called, then drop this call. | 926 // If Stop() has been called, then drop this call. |
| 914 if (!blocking_thread_.IsRunning()) | 927 if (stopped_) |
| 915 return; | 928 return; |
| 916 | 929 |
| 917 // This should only be called after the demuxer has been initialized. | 930 // This should only be called after the demuxer has been initialized. |
| 918 DCHECK_GT(streams_.size(), 0u); | 931 DCHECK_GT(streams_.size(), 0u); |
| 919 | 932 |
| 920 // Abort all outstanding reads. | 933 // Abort all outstanding reads. |
| 921 for (const auto& stream : streams_) { | 934 for (const auto& stream : streams_) { |
| 922 if (stream) | 935 if (stream) |
| 923 stream->Abort(); | 936 stream->Abort(); |
| 924 } | 937 } |
| 925 | 938 |
| 926 // It's important to invalidate read/seek completion callbacks to avoid any | 939 // It's important to invalidate read/seek completion callbacks to avoid any |
| 927 // errors that occur because of the data source abort. | 940 // errors that occur because of the data source abort. |
| 928 weak_factory_.InvalidateWeakPtrs(); | 941 weak_factory_.InvalidateWeakPtrs(); |
| 929 data_source_->Abort(); | 942 data_source_->Abort(); |
| 930 | 943 |
| 931 // Aborting the read may cause EOF to be marked, undo this. | 944 // Aborting the read may cause EOF to be marked, undo this. |
| 932 blocking_thread_.task_runner()->PostTask( | 945 blocking_task_runner_->PostTask( |
| 933 FROM_HERE, base::Bind(&UnmarkEndOfStream, glue_->format_context())); | 946 FROM_HERE, base::Bind(&UnmarkEndOfStream, glue_->format_context())); |
| 934 pending_read_ = false; | 947 pending_read_ = false; |
| 935 | 948 |
| 936 // TODO(dalecurtis): We probably should report PIPELINE_ERROR_ABORT here | 949 // TODO(dalecurtis): We probably should report PIPELINE_ERROR_ABORT here |
| 937 // instead to avoid any preroll work that may be started upon return, but | 950 // instead to avoid any preroll work that may be started upon return, but |
| 938 // currently the PipelineImpl does not know how to handle this. | 951 // currently the PipelineImpl does not know how to handle this. |
| 939 if (!pending_seek_cb_.is_null()) | 952 if (!pending_seek_cb_.is_null()) |
| 940 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_OK); | 953 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_OK); |
| 941 } | 954 } |
| 942 | 955 |
| 943 void FFmpegDemuxer::Stop() { | 956 void FFmpegDemuxer::Stop() { |
| 944 DCHECK(task_runner_->BelongsToCurrentThread()); | 957 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 945 | 958 |
| 946 // The order of Stop() and Abort() is important here. If Abort() is called | 959 // 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 | 960 // first, control may pass into FFmpeg where it can destruct buffers that are |
| 948 // in the process of being fulfilled by the DataSource. | 961 // in the process of being fulfilled by the DataSource. |
| 949 data_source_->Stop(); | 962 data_source_->Stop(); |
| 950 url_protocol_->Abort(); | 963 url_protocol_->Abort(); |
| 951 | 964 |
| 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_) { | 965 for (const auto& stream : streams_) { |
| 959 if (stream) | 966 if (stream) |
| 960 stream->Stop(); | 967 stream->Stop(); |
| 961 } | 968 } |
| 962 | 969 |
| 963 data_source_ = NULL; | 970 data_source_ = NULL; |
| 964 | 971 |
| 965 // Invalidate WeakPtrs on |task_runner_|, destruction may happen on another | 972 // Invalidate WeakPtrs on |task_runner_|, destruction may happen on another |
| 966 // thread. | 973 // thread. We don't need to wait for any outstanding tasks since they will all |
| 974 // fail to return after invalidating WeakPtrs. | |
| 975 stopped_ = true; | |
| 967 weak_factory_.InvalidateWeakPtrs(); | 976 weak_factory_.InvalidateWeakPtrs(); |
| 968 cancel_pending_seek_factory_.InvalidateWeakPtrs(); | 977 cancel_pending_seek_factory_.InvalidateWeakPtrs(); |
| 969 } | 978 } |
| 970 | 979 |
| 971 void FFmpegDemuxer::StartWaitingForSeek(base::TimeDelta seek_time) {} | 980 void FFmpegDemuxer::StartWaitingForSeek(base::TimeDelta seek_time) {} |
| 972 | 981 |
| 973 void FFmpegDemuxer::CancelPendingSeek(base::TimeDelta seek_time) { | 982 void FFmpegDemuxer::CancelPendingSeek(base::TimeDelta seek_time) { |
| 974 if (task_runner_->BelongsToCurrentThread()) { | 983 if (task_runner_->BelongsToCurrentThread()) { |
| 975 AbortPendingReads(); | 984 AbortPendingReads(); |
| 976 } else { | 985 } 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: | 1024 // be demuxed. It's an open question whether FFmpeg should fix this: |
| 1016 // http://lists.ffmpeg.org/pipermail/ffmpeg-devel/2014-June/159212.html | 1025 // http://lists.ffmpeg.org/pipermail/ffmpeg-devel/2014-June/159212.html |
| 1017 // Tracked by http://crbug.com/387996. | 1026 // Tracked by http://crbug.com/387996. |
| 1018 FFmpegDemuxerStream* demux_stream = FindPreferredStreamForSeeking(seek_time); | 1027 FFmpegDemuxerStream* demux_stream = FindPreferredStreamForSeeking(seek_time); |
| 1019 DCHECK(demux_stream); | 1028 DCHECK(demux_stream); |
| 1020 const AVStream* seeking_stream = demux_stream->av_stream(); | 1029 const AVStream* seeking_stream = demux_stream->av_stream(); |
| 1021 DCHECK(seeking_stream); | 1030 DCHECK(seeking_stream); |
| 1022 | 1031 |
| 1023 pending_seek_cb_ = cb; | 1032 pending_seek_cb_ = cb; |
| 1024 base::PostTaskAndReplyWithResult( | 1033 base::PostTaskAndReplyWithResult( |
| 1025 blocking_thread_.task_runner().get(), FROM_HERE, | 1034 blocking_task_runner_.get(), FROM_HERE, |
| 1026 base::Bind(&av_seek_frame, glue_->format_context(), seeking_stream->index, | 1035 base::Bind(&av_seek_frame, glue_->format_context(), seeking_stream->index, |
| 1027 ConvertToTimeBase(seeking_stream->time_base, seek_time), | 1036 ConvertToTimeBase(seeking_stream->time_base, seek_time), |
| 1028 // Always seek to a timestamp <= to the desired timestamp. | 1037 // Always seek to a timestamp <= to the desired timestamp. |
| 1029 AVSEEK_FLAG_BACKWARD), | 1038 AVSEEK_FLAG_BACKWARD), |
| 1030 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, weak_factory_.GetWeakPtr())); | 1039 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, weak_factory_.GetWeakPtr())); |
| 1031 } | 1040 } |
| 1032 | 1041 |
| 1033 base::Time FFmpegDemuxer::GetTimelineOffset() const { | 1042 base::Time FFmpegDemuxer::GetTimelineOffset() const { |
| 1034 return timeline_offset_; | 1043 return timeline_offset_; |
| 1035 } | 1044 } |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1152 // Do math in floating point as we'd overflow an int64_t if the filesize was | 1161 // Do math in floating point as we'd overflow an int64_t if the filesize was |
| 1153 // larger than ~1073GB. | 1162 // larger than ~1073GB. |
| 1154 double bytes = filesize_in_bytes; | 1163 double bytes = filesize_in_bytes; |
| 1155 double duration_us = duration.InMicroseconds(); | 1164 double duration_us = duration.InMicroseconds(); |
| 1156 return bytes * 8000000.0 / duration_us; | 1165 return bytes * 8000000.0 / duration_us; |
| 1157 } | 1166 } |
| 1158 | 1167 |
| 1159 void FFmpegDemuxer::OnOpenContextDone(const PipelineStatusCB& status_cb, | 1168 void FFmpegDemuxer::OnOpenContextDone(const PipelineStatusCB& status_cb, |
| 1160 bool result) { | 1169 bool result) { |
| 1161 DCHECK(task_runner_->BelongsToCurrentThread()); | 1170 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1162 if (!blocking_thread_.IsRunning()) { | 1171 if (stopped_) { |
| 1163 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; | 1172 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; |
| 1164 status_cb.Run(PIPELINE_ERROR_ABORT); | 1173 status_cb.Run(PIPELINE_ERROR_ABORT); |
| 1165 return; | 1174 return; |
| 1166 } | 1175 } |
| 1167 | 1176 |
| 1168 if (!result) { | 1177 if (!result) { |
| 1169 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": open context failed"; | 1178 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": open context failed"; |
| 1170 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN); | 1179 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN); |
| 1171 return; | 1180 return; |
| 1172 } | 1181 } |
| 1173 | 1182 |
| 1174 // Fully initialize AVFormatContext by parsing the stream a little. | 1183 // Fully initialize AVFormatContext by parsing the stream a little. |
| 1175 base::PostTaskAndReplyWithResult( | 1184 base::PostTaskAndReplyWithResult( |
| 1176 blocking_thread_.task_runner().get(), | 1185 blocking_task_runner_.get(), FROM_HERE, |
| 1177 FROM_HERE, | 1186 base::Bind(&avformat_find_stream_info, glue_->format_context(), |
| 1178 base::Bind(&avformat_find_stream_info, | |
| 1179 glue_->format_context(), | |
| 1180 static_cast<AVDictionary**>(NULL)), | 1187 static_cast<AVDictionary**>(NULL)), |
| 1181 base::Bind(&FFmpegDemuxer::OnFindStreamInfoDone, | 1188 base::Bind(&FFmpegDemuxer::OnFindStreamInfoDone, |
| 1182 weak_factory_.GetWeakPtr(), | 1189 weak_factory_.GetWeakPtr(), status_cb)); |
| 1183 status_cb)); | |
| 1184 } | 1190 } |
| 1185 | 1191 |
| 1186 void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, | 1192 void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, |
| 1187 int result) { | 1193 int result) { |
| 1188 DCHECK(task_runner_->BelongsToCurrentThread()); | 1194 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1189 if (!blocking_thread_.IsRunning() || !data_source_) { | 1195 if (stopped_ || !data_source_) { |
| 1190 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; | 1196 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; |
| 1191 status_cb.Run(PIPELINE_ERROR_ABORT); | 1197 status_cb.Run(PIPELINE_ERROR_ABORT); |
| 1192 return; | 1198 return; |
| 1193 } | 1199 } |
| 1194 | 1200 |
| 1195 if (result < 0) { | 1201 if (result < 0) { |
| 1196 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() | 1202 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() |
| 1197 << ": find stream info failed"; | 1203 << ": find stream info failed"; |
| 1198 status_cb.Run(DEMUXER_ERROR_COULD_NOT_PARSE); | 1204 status_cb.Run(DEMUXER_ERROR_COULD_NOT_PARSE); |
| 1199 return; | 1205 return; |
| (...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1599 } | 1605 } |
| 1600 | 1606 |
| 1601 NOTREACHED(); | 1607 NOTREACHED(); |
| 1602 return nullptr; | 1608 return nullptr; |
| 1603 } | 1609 } |
| 1604 | 1610 |
| 1605 void FFmpegDemuxer::OnSeekFrameDone(int result) { | 1611 void FFmpegDemuxer::OnSeekFrameDone(int result) { |
| 1606 DCHECK(task_runner_->BelongsToCurrentThread()); | 1612 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1607 CHECK(!pending_seek_cb_.is_null()); | 1613 CHECK(!pending_seek_cb_.is_null()); |
| 1608 | 1614 |
| 1609 if (!blocking_thread_.IsRunning()) { | 1615 if (stopped_) { |
| 1610 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; | 1616 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; |
| 1611 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_ERROR_ABORT); | 1617 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_ERROR_ABORT); |
| 1612 return; | 1618 return; |
| 1613 } | 1619 } |
| 1614 | 1620 |
| 1615 if (result < 0) { | 1621 if (result < 0) { |
| 1616 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being | 1622 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being |
| 1617 // captured from stdout and contaminates testing. | 1623 // captured from stdout and contaminates testing. |
| 1618 // TODO(scherkus): Implement this properly and signal error (BUG=23447). | 1624 // TODO(scherkus): Implement this properly and signal error (BUG=23447). |
| 1619 VLOG(1) << "Not implemented"; | 1625 VLOG(1) << "Not implemented"; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1686 if (selected_stream) { | 1692 if (selected_stream) { |
| 1687 DVLOG(1) << __func__ << ": enabling stream " << selected_stream; | 1693 DVLOG(1) << __func__ << ": enabling stream " << selected_stream; |
| 1688 selected_stream->set_enabled(true, currTime); | 1694 selected_stream->set_enabled(true, currTime); |
| 1689 } | 1695 } |
| 1690 } | 1696 } |
| 1691 | 1697 |
| 1692 void FFmpegDemuxer::ReadFrameIfNeeded() { | 1698 void FFmpegDemuxer::ReadFrameIfNeeded() { |
| 1693 DCHECK(task_runner_->BelongsToCurrentThread()); | 1699 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1694 | 1700 |
| 1695 // Make sure we have work to do before reading. | 1701 // Make sure we have work to do before reading. |
| 1696 if (!blocking_thread_.IsRunning() || !StreamsHaveAvailableCapacity() || | 1702 if (stopped_ || !StreamsHaveAvailableCapacity() || pending_read_ || |
| 1697 pending_read_ || !pending_seek_cb_.is_null()) { | 1703 !pending_seek_cb_.is_null()) { |
| 1698 return; | 1704 return; |
| 1699 } | 1705 } |
| 1700 | 1706 |
| 1701 // Allocate and read an AVPacket from the media. Save |packet_ptr| since | 1707 // Allocate and read an AVPacket from the media. Save |packet_ptr| since |
| 1702 // evaluation order of packet.get() and base::Passed(&packet) is | 1708 // evaluation order of packet.get() and base::Passed(&packet) is |
| 1703 // undefined. | 1709 // undefined. |
| 1704 ScopedAVPacket packet(new AVPacket()); | 1710 ScopedAVPacket packet(new AVPacket()); |
| 1705 AVPacket* packet_ptr = packet.get(); | 1711 AVPacket* packet_ptr = packet.get(); |
| 1706 | 1712 |
| 1707 pending_read_ = true; | 1713 pending_read_ = true; |
| 1708 base::PostTaskAndReplyWithResult( | 1714 base::PostTaskAndReplyWithResult( |
| 1709 blocking_thread_.task_runner().get(), | 1715 blocking_task_runner_.get(), FROM_HERE, |
| 1710 FROM_HERE, | |
| 1711 base::Bind(&av_read_frame, glue_->format_context(), packet_ptr), | 1716 base::Bind(&av_read_frame, glue_->format_context(), packet_ptr), |
| 1712 base::Bind(&FFmpegDemuxer::OnReadFrameDone, | 1717 base::Bind(&FFmpegDemuxer::OnReadFrameDone, weak_factory_.GetWeakPtr(), |
| 1713 weak_factory_.GetWeakPtr(), | |
| 1714 base::Passed(&packet))); | 1718 base::Passed(&packet))); |
| 1715 } | 1719 } |
| 1716 | 1720 |
| 1717 void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) { | 1721 void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) { |
| 1718 DCHECK(task_runner_->BelongsToCurrentThread()); | 1722 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1719 DCHECK(pending_read_); | 1723 DCHECK(pending_read_); |
| 1720 pending_read_ = false; | 1724 pending_read_ = false; |
| 1721 | 1725 |
| 1722 if (!blocking_thread_.IsRunning() || !pending_seek_cb_.is_null()) | 1726 if (stopped_ || !pending_seek_cb_.is_null()) |
| 1723 return; | 1727 return; |
| 1724 | 1728 |
| 1725 // Consider the stream as ended if: | 1729 // Consider the stream as ended if: |
| 1726 // - either underlying ffmpeg returned an error | 1730 // - either underlying ffmpeg returned an error |
| 1727 // - or FFMpegDemuxer reached the maximum allowed memory usage. | 1731 // - or FFMpegDemuxer reached the maximum allowed memory usage. |
| 1728 if (result < 0 || IsMaxMemoryUsageReached()) { | 1732 if (result < 0 || IsMaxMemoryUsageReached()) { |
| 1729 DVLOG(1) << __func__ << " result=" << result | 1733 DVLOG(1) << __func__ << " result=" << result |
| 1730 << " IsMaxMemoryUsageReached=" << IsMaxMemoryUsageReached(); | 1734 << " IsMaxMemoryUsageReached=" << IsMaxMemoryUsageReached(); |
| 1731 // Update the duration based on the highest elapsed time across all streams. | 1735 // Update the duration based on the highest elapsed time across all streams. |
| 1732 base::TimeDelta max_duration; | 1736 base::TimeDelta max_duration; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1837 | 1841 |
| 1838 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { | 1842 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { |
| 1839 DCHECK(task_runner_->BelongsToCurrentThread()); | 1843 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1840 for (const auto& stream : streams_) { | 1844 for (const auto& stream : streams_) { |
| 1841 if (stream) | 1845 if (stream) |
| 1842 stream->SetLiveness(liveness); | 1846 stream->SetLiveness(liveness); |
| 1843 } | 1847 } |
| 1844 } | 1848 } |
| 1845 | 1849 |
| 1846 } // namespace media | 1850 } // namespace media |
| OLD | NEW |