| 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" | |
| 27 #include "base/threading/thread_task_runner_handle.h" | 25 #include "base/threading/thread_task_runner_handle.h" |
| 28 #include "base/time/time.h" | 26 #include "base/time/time.h" |
| 29 #include "media/audio/sample_rates.h" | 27 #include "media/audio/sample_rates.h" |
| 30 #include "media/base/bind_to_current_loop.h" | 28 #include "media/base/bind_to_current_loop.h" |
| 31 #include "media/base/decrypt_config.h" | 29 #include "media/base/decrypt_config.h" |
| 32 #include "media/base/limits.h" | 30 #include "media/base/limits.h" |
| 33 #include "media/base/media_log.h" | 31 #include "media/base/media_log.h" |
| 34 #include "media/base/media_tracks.h" | 32 #include "media/base/media_tracks.h" |
| 35 #include "media/base/timestamp_constants.h" | 33 #include "media/base/timestamp_constants.h" |
| 36 #include "media/base/video_codecs.h" | 34 #include "media/base/video_codecs.h" |
| (...skipping 803 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 840 // FFmpegDemuxer | 838 // FFmpegDemuxer |
| 841 // | 839 // |
| 842 FFmpegDemuxer::FFmpegDemuxer( | 840 FFmpegDemuxer::FFmpegDemuxer( |
| 843 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 841 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| 844 DataSource* data_source, | 842 DataSource* data_source, |
| 845 const EncryptedMediaInitDataCB& encrypted_media_init_data_cb, | 843 const EncryptedMediaInitDataCB& encrypted_media_init_data_cb, |
| 846 const MediaTracksUpdatedCB& media_tracks_updated_cb, | 844 const MediaTracksUpdatedCB& media_tracks_updated_cb, |
| 847 const scoped_refptr<MediaLog>& media_log) | 845 const scoped_refptr<MediaLog>& media_log) |
| 848 : host_(NULL), | 846 : host_(NULL), |
| 849 task_runner_(task_runner), | 847 task_runner_(task_runner), |
| 850 // FFmpeg has no asynchronous API, so we use base::WaitableEvents inside | 848 blocking_thread_("FFmpegDemuxer"), |
| 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), | |
| 857 pending_read_(false), | 849 pending_read_(false), |
| 858 data_source_(data_source), | 850 data_source_(data_source), |
| 859 media_log_(media_log), | 851 media_log_(media_log), |
| 860 bitrate_(0), | 852 bitrate_(0), |
| 861 start_time_(kNoTimestamp), | 853 start_time_(kNoTimestamp), |
| 862 text_enabled_(false), | 854 text_enabled_(false), |
| 863 duration_known_(false), | 855 duration_known_(false), |
| 864 encrypted_media_init_data_cb_(encrypted_media_init_data_cb), | 856 encrypted_media_init_data_cb_(encrypted_media_init_data_cb), |
| 865 media_tracks_updated_cb_(media_tracks_updated_cb), | 857 media_tracks_updated_cb_(media_tracks_updated_cb), |
| 866 cancel_pending_seek_factory_(this), | 858 cancel_pending_seek_factory_(this), |
| 867 weak_factory_(this) { | 859 weak_factory_(this) { |
| 868 DCHECK(task_runner_.get()); | 860 DCHECK(task_runner_.get()); |
| 869 DCHECK(data_source_); | 861 DCHECK(data_source_); |
| 870 DCHECK(!media_tracks_updated_cb_.is_null()); | 862 DCHECK(!media_tracks_updated_cb_.is_null()); |
| 871 } | 863 } |
| 872 | 864 |
| 873 FFmpegDemuxer::~FFmpegDemuxer() { | 865 FFmpegDemuxer::~FFmpegDemuxer() { |
| 874 // NOTE: This class is not destroyed on |task_runner|, so we must ensure that | 866 // NOTE: This class is not destroyed on |task_runner|, so we must ensure that |
| 875 // there are no outstanding WeakPtrs by the time we reach here. | 867 // there are no outstanding WeakPtrs by the time we reach here. |
| 876 DCHECK(!weak_factory_.HasWeakPtrs()); | 868 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()); | |
| 883 } | 869 } |
| 884 | 870 |
| 885 std::string FFmpegDemuxer::GetDisplayName() const { | 871 std::string FFmpegDemuxer::GetDisplayName() const { |
| 886 return "FFmpegDemuxer"; | 872 return "FFmpegDemuxer"; |
| 887 } | 873 } |
| 888 | 874 |
| 889 void FFmpegDemuxer::Initialize(DemuxerHost* host, | 875 void FFmpegDemuxer::Initialize(DemuxerHost* host, |
| 890 const PipelineStatusCB& status_cb, | 876 const PipelineStatusCB& status_cb, |
| 891 bool enable_text_tracks) { | 877 bool enable_text_tracks) { |
| 892 DCHECK(task_runner_->BelongsToCurrentThread()); | 878 DCHECK(task_runner_->BelongsToCurrentThread()); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 906 // available, so add a metadata entry to ensure some is always present. | 892 // available, so add a metadata entry to ensure some is always present. |
| 907 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0); | 893 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0); |
| 908 | 894 |
| 909 // Ensure ffmpeg doesn't give up too early while looking for stream params; | 895 // Ensure ffmpeg doesn't give up too early while looking for stream params; |
| 910 // this does not increase the amount of data downloaded. The default value | 896 // this does not increase the amount of data downloaded. The default value |
| 911 // is 5 AV_TIME_BASE units (1 second each), which prevents some oddly muxed | 897 // is 5 AV_TIME_BASE units (1 second each), which prevents some oddly muxed |
| 912 // streams from being detected properly; this value was chosen arbitrarily. | 898 // streams from being detected properly; this value was chosen arbitrarily. |
| 913 format_context->max_analyze_duration = 60 * AV_TIME_BASE; | 899 format_context->max_analyze_duration = 60 * AV_TIME_BASE; |
| 914 | 900 |
| 915 // Open the AVFormatContext using our glue layer. | 901 // Open the AVFormatContext using our glue layer. |
| 902 CHECK(blocking_thread_.Start()); |
| 916 base::PostTaskAndReplyWithResult( | 903 base::PostTaskAndReplyWithResult( |
| 917 blocking_task_runner_.get(), FROM_HERE, | 904 blocking_thread_.task_runner().get(), FROM_HERE, |
| 918 base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())), | 905 base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())), |
| 919 base::Bind(&FFmpegDemuxer::OnOpenContextDone, weak_factory_.GetWeakPtr(), | 906 base::Bind(&FFmpegDemuxer::OnOpenContextDone, weak_factory_.GetWeakPtr(), |
| 920 status_cb)); | 907 status_cb)); |
| 921 } | 908 } |
| 922 | 909 |
| 923 void FFmpegDemuxer::AbortPendingReads() { | 910 void FFmpegDemuxer::AbortPendingReads() { |
| 924 DCHECK(task_runner_->BelongsToCurrentThread()); | 911 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 925 | 912 |
| 926 // If Stop() has been called, then drop this call. | 913 // If Stop() has been called, then drop this call. |
| 927 if (stopped_) | 914 if (!blocking_thread_.IsRunning()) |
| 928 return; | 915 return; |
| 929 | 916 |
| 930 // This should only be called after the demuxer has been initialized. | 917 // This should only be called after the demuxer has been initialized. |
| 931 DCHECK_GT(streams_.size(), 0u); | 918 DCHECK_GT(streams_.size(), 0u); |
| 932 | 919 |
| 933 // Abort all outstanding reads. | 920 // Abort all outstanding reads. |
| 934 for (const auto& stream : streams_) { | 921 for (const auto& stream : streams_) { |
| 935 if (stream) | 922 if (stream) |
| 936 stream->Abort(); | 923 stream->Abort(); |
| 937 } | 924 } |
| 938 | 925 |
| 939 // It's important to invalidate read/seek completion callbacks to avoid any | 926 // It's important to invalidate read/seek completion callbacks to avoid any |
| 940 // errors that occur because of the data source abort. | 927 // errors that occur because of the data source abort. |
| 941 weak_factory_.InvalidateWeakPtrs(); | 928 weak_factory_.InvalidateWeakPtrs(); |
| 942 data_source_->Abort(); | 929 data_source_->Abort(); |
| 943 | 930 |
| 944 // Aborting the read may cause EOF to be marked, undo this. | 931 // Aborting the read may cause EOF to be marked, undo this. |
| 945 blocking_task_runner_->PostTask( | 932 blocking_thread_.task_runner()->PostTask( |
| 946 FROM_HERE, base::Bind(&UnmarkEndOfStream, glue_->format_context())); | 933 FROM_HERE, base::Bind(&UnmarkEndOfStream, glue_->format_context())); |
| 947 pending_read_ = false; | 934 pending_read_ = false; |
| 948 | 935 |
| 949 // TODO(dalecurtis): We probably should report PIPELINE_ERROR_ABORT here | 936 // TODO(dalecurtis): We probably should report PIPELINE_ERROR_ABORT here |
| 950 // instead to avoid any preroll work that may be started upon return, but | 937 // instead to avoid any preroll work that may be started upon return, but |
| 951 // currently the PipelineImpl does not know how to handle this. | 938 // currently the PipelineImpl does not know how to handle this. |
| 952 if (!pending_seek_cb_.is_null()) | 939 if (!pending_seek_cb_.is_null()) |
| 953 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_OK); | 940 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_OK); |
| 954 } | 941 } |
| 955 | 942 |
| 956 void FFmpegDemuxer::Stop() { | 943 void FFmpegDemuxer::Stop() { |
| 957 DCHECK(task_runner_->BelongsToCurrentThread()); | 944 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 958 | 945 |
| 959 // The order of Stop() and Abort() is important here. If Abort() is called | 946 // The order of Stop() and Abort() is important here. If Abort() is called |
| 960 // first, control may pass into FFmpeg where it can destruct buffers that are | 947 // first, control may pass into FFmpeg where it can destruct buffers that are |
| 961 // in the process of being fulfilled by the DataSource. | 948 // in the process of being fulfilled by the DataSource. |
| 962 data_source_->Stop(); | 949 data_source_->Stop(); |
| 963 url_protocol_->Abort(); | 950 url_protocol_->Abort(); |
| 964 | 951 |
| 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 |
| 965 for (const auto& stream : streams_) { | 958 for (const auto& stream : streams_) { |
| 966 if (stream) | 959 if (stream) |
| 967 stream->Stop(); | 960 stream->Stop(); |
| 968 } | 961 } |
| 969 | 962 |
| 970 data_source_ = NULL; | 963 data_source_ = NULL; |
| 971 | 964 |
| 972 // Invalidate WeakPtrs on |task_runner_|, destruction may happen on another | 965 // Invalidate WeakPtrs on |task_runner_|, destruction may happen on another |
| 973 // thread. We don't need to wait for any outstanding tasks since they will all | 966 // thread. |
| 974 // fail to return after invalidating WeakPtrs. | |
| 975 stopped_ = true; | |
| 976 weak_factory_.InvalidateWeakPtrs(); | 967 weak_factory_.InvalidateWeakPtrs(); |
| 977 cancel_pending_seek_factory_.InvalidateWeakPtrs(); | 968 cancel_pending_seek_factory_.InvalidateWeakPtrs(); |
| 978 } | 969 } |
| 979 | 970 |
| 980 void FFmpegDemuxer::StartWaitingForSeek(base::TimeDelta seek_time) {} | 971 void FFmpegDemuxer::StartWaitingForSeek(base::TimeDelta seek_time) {} |
| 981 | 972 |
| 982 void FFmpegDemuxer::CancelPendingSeek(base::TimeDelta seek_time) { | 973 void FFmpegDemuxer::CancelPendingSeek(base::TimeDelta seek_time) { |
| 983 if (task_runner_->BelongsToCurrentThread()) { | 974 if (task_runner_->BelongsToCurrentThread()) { |
| 984 AbortPendingReads(); | 975 AbortPendingReads(); |
| 985 } else { | 976 } else { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1024 // be demuxed. It's an open question whether FFmpeg should fix this: | 1015 // be demuxed. It's an open question whether FFmpeg should fix this: |
| 1025 // http://lists.ffmpeg.org/pipermail/ffmpeg-devel/2014-June/159212.html | 1016 // http://lists.ffmpeg.org/pipermail/ffmpeg-devel/2014-June/159212.html |
| 1026 // Tracked by http://crbug.com/387996. | 1017 // Tracked by http://crbug.com/387996. |
| 1027 FFmpegDemuxerStream* demux_stream = FindPreferredStreamForSeeking(seek_time); | 1018 FFmpegDemuxerStream* demux_stream = FindPreferredStreamForSeeking(seek_time); |
| 1028 DCHECK(demux_stream); | 1019 DCHECK(demux_stream); |
| 1029 const AVStream* seeking_stream = demux_stream->av_stream(); | 1020 const AVStream* seeking_stream = demux_stream->av_stream(); |
| 1030 DCHECK(seeking_stream); | 1021 DCHECK(seeking_stream); |
| 1031 | 1022 |
| 1032 pending_seek_cb_ = cb; | 1023 pending_seek_cb_ = cb; |
| 1033 base::PostTaskAndReplyWithResult( | 1024 base::PostTaskAndReplyWithResult( |
| 1034 blocking_task_runner_.get(), FROM_HERE, | 1025 blocking_thread_.task_runner().get(), FROM_HERE, |
| 1035 base::Bind(&av_seek_frame, glue_->format_context(), seeking_stream->index, | 1026 base::Bind(&av_seek_frame, glue_->format_context(), seeking_stream->index, |
| 1036 ConvertToTimeBase(seeking_stream->time_base, seek_time), | 1027 ConvertToTimeBase(seeking_stream->time_base, seek_time), |
| 1037 // Always seek to a timestamp <= to the desired timestamp. | 1028 // Always seek to a timestamp <= to the desired timestamp. |
| 1038 AVSEEK_FLAG_BACKWARD), | 1029 AVSEEK_FLAG_BACKWARD), |
| 1039 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, weak_factory_.GetWeakPtr())); | 1030 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, weak_factory_.GetWeakPtr())); |
| 1040 } | 1031 } |
| 1041 | 1032 |
| 1042 base::Time FFmpegDemuxer::GetTimelineOffset() const { | 1033 base::Time FFmpegDemuxer::GetTimelineOffset() const { |
| 1043 return timeline_offset_; | 1034 return timeline_offset_; |
| 1044 } | 1035 } |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1161 // Do math in floating point as we'd overflow an int64_t if the filesize was | 1152 // Do math in floating point as we'd overflow an int64_t if the filesize was |
| 1162 // larger than ~1073GB. | 1153 // larger than ~1073GB. |
| 1163 double bytes = filesize_in_bytes; | 1154 double bytes = filesize_in_bytes; |
| 1164 double duration_us = duration.InMicroseconds(); | 1155 double duration_us = duration.InMicroseconds(); |
| 1165 return bytes * 8000000.0 / duration_us; | 1156 return bytes * 8000000.0 / duration_us; |
| 1166 } | 1157 } |
| 1167 | 1158 |
| 1168 void FFmpegDemuxer::OnOpenContextDone(const PipelineStatusCB& status_cb, | 1159 void FFmpegDemuxer::OnOpenContextDone(const PipelineStatusCB& status_cb, |
| 1169 bool result) { | 1160 bool result) { |
| 1170 DCHECK(task_runner_->BelongsToCurrentThread()); | 1161 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1171 if (stopped_) { | 1162 if (!blocking_thread_.IsRunning()) { |
| 1172 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; | 1163 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; |
| 1173 status_cb.Run(PIPELINE_ERROR_ABORT); | 1164 status_cb.Run(PIPELINE_ERROR_ABORT); |
| 1174 return; | 1165 return; |
| 1175 } | 1166 } |
| 1176 | 1167 |
| 1177 if (!result) { | 1168 if (!result) { |
| 1178 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": open context failed"; | 1169 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": open context failed"; |
| 1179 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN); | 1170 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN); |
| 1180 return; | 1171 return; |
| 1181 } | 1172 } |
| 1182 | 1173 |
| 1183 // Fully initialize AVFormatContext by parsing the stream a little. | 1174 // Fully initialize AVFormatContext by parsing the stream a little. |
| 1184 base::PostTaskAndReplyWithResult( | 1175 base::PostTaskAndReplyWithResult( |
| 1185 blocking_task_runner_.get(), FROM_HERE, | 1176 blocking_thread_.task_runner().get(), |
| 1186 base::Bind(&avformat_find_stream_info, glue_->format_context(), | 1177 FROM_HERE, |
| 1178 base::Bind(&avformat_find_stream_info, |
| 1179 glue_->format_context(), |
| 1187 static_cast<AVDictionary**>(NULL)), | 1180 static_cast<AVDictionary**>(NULL)), |
| 1188 base::Bind(&FFmpegDemuxer::OnFindStreamInfoDone, | 1181 base::Bind(&FFmpegDemuxer::OnFindStreamInfoDone, |
| 1189 weak_factory_.GetWeakPtr(), status_cb)); | 1182 weak_factory_.GetWeakPtr(), |
| 1183 status_cb)); |
| 1190 } | 1184 } |
| 1191 | 1185 |
| 1192 void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, | 1186 void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, |
| 1193 int result) { | 1187 int result) { |
| 1194 DCHECK(task_runner_->BelongsToCurrentThread()); | 1188 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1195 if (stopped_ || !data_source_) { | 1189 if (!blocking_thread_.IsRunning() || !data_source_) { |
| 1196 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; | 1190 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; |
| 1197 status_cb.Run(PIPELINE_ERROR_ABORT); | 1191 status_cb.Run(PIPELINE_ERROR_ABORT); |
| 1198 return; | 1192 return; |
| 1199 } | 1193 } |
| 1200 | 1194 |
| 1201 if (result < 0) { | 1195 if (result < 0) { |
| 1202 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() | 1196 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() |
| 1203 << ": find stream info failed"; | 1197 << ": find stream info failed"; |
| 1204 status_cb.Run(DEMUXER_ERROR_COULD_NOT_PARSE); | 1198 status_cb.Run(DEMUXER_ERROR_COULD_NOT_PARSE); |
| 1205 return; | 1199 return; |
| (...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1605 } | 1599 } |
| 1606 | 1600 |
| 1607 NOTREACHED(); | 1601 NOTREACHED(); |
| 1608 return nullptr; | 1602 return nullptr; |
| 1609 } | 1603 } |
| 1610 | 1604 |
| 1611 void FFmpegDemuxer::OnSeekFrameDone(int result) { | 1605 void FFmpegDemuxer::OnSeekFrameDone(int result) { |
| 1612 DCHECK(task_runner_->BelongsToCurrentThread()); | 1606 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1613 CHECK(!pending_seek_cb_.is_null()); | 1607 CHECK(!pending_seek_cb_.is_null()); |
| 1614 | 1608 |
| 1615 if (stopped_) { | 1609 if (!blocking_thread_.IsRunning()) { |
| 1616 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; | 1610 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; |
| 1617 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_ERROR_ABORT); | 1611 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_ERROR_ABORT); |
| 1618 return; | 1612 return; |
| 1619 } | 1613 } |
| 1620 | 1614 |
| 1621 if (result < 0) { | 1615 if (result < 0) { |
| 1622 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being | 1616 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being |
| 1623 // captured from stdout and contaminates testing. | 1617 // captured from stdout and contaminates testing. |
| 1624 // TODO(scherkus): Implement this properly and signal error (BUG=23447). | 1618 // TODO(scherkus): Implement this properly and signal error (BUG=23447). |
| 1625 VLOG(1) << "Not implemented"; | 1619 VLOG(1) << "Not implemented"; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1691 if (selected_stream) { | 1685 if (selected_stream) { |
| 1692 DVLOG(1) << __func__ << ": enabling stream " << selected_stream; | 1686 DVLOG(1) << __func__ << ": enabling stream " << selected_stream; |
| 1693 selected_stream->set_enabled(true, curr_time); | 1687 selected_stream->set_enabled(true, curr_time); |
| 1694 } | 1688 } |
| 1695 } | 1689 } |
| 1696 | 1690 |
| 1697 void FFmpegDemuxer::ReadFrameIfNeeded() { | 1691 void FFmpegDemuxer::ReadFrameIfNeeded() { |
| 1698 DCHECK(task_runner_->BelongsToCurrentThread()); | 1692 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1699 | 1693 |
| 1700 // Make sure we have work to do before reading. | 1694 // Make sure we have work to do before reading. |
| 1701 if (stopped_ || !StreamsHaveAvailableCapacity() || pending_read_ || | 1695 if (!blocking_thread_.IsRunning() || !StreamsHaveAvailableCapacity() || |
| 1702 !pending_seek_cb_.is_null()) { | 1696 pending_read_ || !pending_seek_cb_.is_null()) { |
| 1703 return; | 1697 return; |
| 1704 } | 1698 } |
| 1705 | 1699 |
| 1706 // Allocate and read an AVPacket from the media. Save |packet_ptr| since | 1700 // Allocate and read an AVPacket from the media. Save |packet_ptr| since |
| 1707 // evaluation order of packet.get() and base::Passed(&packet) is | 1701 // evaluation order of packet.get() and base::Passed(&packet) is |
| 1708 // undefined. | 1702 // undefined. |
| 1709 ScopedAVPacket packet(new AVPacket()); | 1703 ScopedAVPacket packet(new AVPacket()); |
| 1710 AVPacket* packet_ptr = packet.get(); | 1704 AVPacket* packet_ptr = packet.get(); |
| 1711 | 1705 |
| 1712 pending_read_ = true; | 1706 pending_read_ = true; |
| 1713 base::PostTaskAndReplyWithResult( | 1707 base::PostTaskAndReplyWithResult( |
| 1714 blocking_task_runner_.get(), FROM_HERE, | 1708 blocking_thread_.task_runner().get(), |
| 1709 FROM_HERE, |
| 1715 base::Bind(&av_read_frame, glue_->format_context(), packet_ptr), | 1710 base::Bind(&av_read_frame, glue_->format_context(), packet_ptr), |
| 1716 base::Bind(&FFmpegDemuxer::OnReadFrameDone, weak_factory_.GetWeakPtr(), | 1711 base::Bind(&FFmpegDemuxer::OnReadFrameDone, |
| 1712 weak_factory_.GetWeakPtr(), |
| 1717 base::Passed(&packet))); | 1713 base::Passed(&packet))); |
| 1718 } | 1714 } |
| 1719 | 1715 |
| 1720 void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) { | 1716 void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) { |
| 1721 DCHECK(task_runner_->BelongsToCurrentThread()); | 1717 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1722 DCHECK(pending_read_); | 1718 DCHECK(pending_read_); |
| 1723 pending_read_ = false; | 1719 pending_read_ = false; |
| 1724 | 1720 |
| 1725 if (stopped_ || !pending_seek_cb_.is_null()) | 1721 if (!blocking_thread_.IsRunning() || !pending_seek_cb_.is_null()) |
| 1726 return; | 1722 return; |
| 1727 | 1723 |
| 1728 // Consider the stream as ended if: | 1724 // Consider the stream as ended if: |
| 1729 // - either underlying ffmpeg returned an error | 1725 // - either underlying ffmpeg returned an error |
| 1730 // - or FFMpegDemuxer reached the maximum allowed memory usage. | 1726 // - or FFMpegDemuxer reached the maximum allowed memory usage. |
| 1731 if (result < 0 || IsMaxMemoryUsageReached()) { | 1727 if (result < 0 || IsMaxMemoryUsageReached()) { |
| 1732 DVLOG(1) << __func__ << " result=" << result | 1728 DVLOG(1) << __func__ << " result=" << result |
| 1733 << " IsMaxMemoryUsageReached=" << IsMaxMemoryUsageReached(); | 1729 << " IsMaxMemoryUsageReached=" << IsMaxMemoryUsageReached(); |
| 1734 // Update the duration based on the highest elapsed time across all streams. | 1730 // Update the duration based on the highest elapsed time across all streams. |
| 1735 base::TimeDelta max_duration; | 1731 base::TimeDelta max_duration; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1840 | 1836 |
| 1841 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { | 1837 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { |
| 1842 DCHECK(task_runner_->BelongsToCurrentThread()); | 1838 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1843 for (const auto& stream : streams_) { | 1839 for (const auto& stream : streams_) { |
| 1844 if (stream) | 1840 if (stream) |
| 1845 stream->SetLiveness(liveness); | 1841 stream->SetLiveness(liveness); |
| 1846 } | 1842 } |
| 1847 } | 1843 } |
| 1848 | 1844 |
| 1849 } // namespace media | 1845 } // namespace media |
| OLD | NEW |