| 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 <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 881 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 892 DCHECK(task_runner_->BelongsToCurrentThread()); | 892 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 893 | 893 |
| 894 // If Stop() has been called, then drop this call. | 894 // If Stop() has been called, then drop this call. |
| 895 if (!blocking_thread_.IsRunning()) | 895 if (!blocking_thread_.IsRunning()) |
| 896 return; | 896 return; |
| 897 | 897 |
| 898 // This should only be called after the demuxer has been initialized. | 898 // This should only be called after the demuxer has been initialized. |
| 899 DCHECK_GT(streams_.size(), 0u); | 899 DCHECK_GT(streams_.size(), 0u); |
| 900 | 900 |
| 901 // Abort all outstanding reads. | 901 // Abort all outstanding reads. |
| 902 for (auto* stream : streams_) { | 902 for (const auto& stream : streams_) { |
| 903 if (stream) | 903 if (stream) |
| 904 stream->Abort(); | 904 stream->Abort(); |
| 905 } | 905 } |
| 906 | 906 |
| 907 // It's important to invalidate read/seek completion callbacks to avoid any | 907 // It's important to invalidate read/seek completion callbacks to avoid any |
| 908 // errors that occur because of the data source abort. | 908 // errors that occur because of the data source abort. |
| 909 weak_factory_.InvalidateWeakPtrs(); | 909 weak_factory_.InvalidateWeakPtrs(); |
| 910 data_source_->Abort(); | 910 data_source_->Abort(); |
| 911 | 911 |
| 912 // Aborting the read may cause EOF to be marked, undo this. | 912 // Aborting the read may cause EOF to be marked, undo this. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 929 // in the process of being fulfilled by the DataSource. | 929 // in the process of being fulfilled by the DataSource. |
| 930 data_source_->Stop(); | 930 data_source_->Stop(); |
| 931 url_protocol_->Abort(); | 931 url_protocol_->Abort(); |
| 932 | 932 |
| 933 // This will block until all tasks complete. Note that after this returns it's | 933 // This will block until all tasks complete. Note that after this returns it's |
| 934 // possible for reply tasks (e.g., OnReadFrameDone()) to be queued on this | 934 // possible for reply tasks (e.g., OnReadFrameDone()) to be queued on this |
| 935 // thread. Each of the reply task methods must check whether we've stopped the | 935 // thread. Each of the reply task methods must check whether we've stopped the |
| 936 // thread and drop their results on the floor. | 936 // thread and drop their results on the floor. |
| 937 blocking_thread_.Stop(); | 937 blocking_thread_.Stop(); |
| 938 | 938 |
| 939 StreamVector::iterator iter; | 939 for (const auto& stream : streams_) { |
| 940 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 940 if (stream) |
| 941 if (*iter) | 941 stream->Stop(); |
| 942 (*iter)->Stop(); | |
| 943 } | 942 } |
| 944 | 943 |
| 945 data_source_ = NULL; | 944 data_source_ = NULL; |
| 946 | 945 |
| 947 // Invalidate WeakPtrs on |task_runner_|, destruction may happen on another | 946 // Invalidate WeakPtrs on |task_runner_|, destruction may happen on another |
| 948 // thread. | 947 // thread. |
| 949 weak_factory_.InvalidateWeakPtrs(); | 948 weak_factory_.InvalidateWeakPtrs(); |
| 950 } | 949 } |
| 951 | 950 |
| 952 void FFmpegDemuxer::StartWaitingForSeek(base::TimeDelta seek_time) {} | 951 void FFmpegDemuxer::StartWaitingForSeek(base::TimeDelta seek_time) {} |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1014 return timeline_offset_; | 1013 return timeline_offset_; |
| 1015 } | 1014 } |
| 1016 | 1015 |
| 1017 DemuxerStream* FFmpegDemuxer::GetStream(DemuxerStream::Type type) { | 1016 DemuxerStream* FFmpegDemuxer::GetStream(DemuxerStream::Type type) { |
| 1018 DCHECK(task_runner_->BelongsToCurrentThread()); | 1017 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1019 return GetFFmpegStream(type); | 1018 return GetFFmpegStream(type); |
| 1020 } | 1019 } |
| 1021 | 1020 |
| 1022 FFmpegDemuxerStream* FFmpegDemuxer::GetFFmpegStream( | 1021 FFmpegDemuxerStream* FFmpegDemuxer::GetFFmpegStream( |
| 1023 DemuxerStream::Type type) const { | 1022 DemuxerStream::Type type) const { |
| 1024 StreamVector::const_iterator iter; | 1023 for (const auto& stream : streams_) { |
| 1025 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 1024 if (stream && stream->type() == type && stream->enabled()) { |
| 1026 if (*iter && (*iter)->type() == type) { | 1025 return stream.get(); |
| 1027 return *iter; | |
| 1028 } | 1026 } |
| 1029 } | 1027 } |
| 1030 return NULL; | 1028 return NULL; |
| 1031 } | 1029 } |
| 1032 | 1030 |
| 1033 base::TimeDelta FFmpegDemuxer::GetStartTime() const { | 1031 base::TimeDelta FFmpegDemuxer::GetStartTime() const { |
| 1034 return std::max(start_time_, base::TimeDelta()); | 1032 return std::max(start_time_, base::TimeDelta()); |
| 1035 } | 1033 } |
| 1036 | 1034 |
| 1037 void FFmpegDemuxer::AddTextStreams() { | 1035 void FFmpegDemuxer::AddTextStreams() { |
| 1038 DCHECK(task_runner_->BelongsToCurrentThread()); | 1036 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1039 | 1037 |
| 1040 for (StreamVector::size_type idx = 0; idx < streams_.size(); ++idx) { | 1038 for (const auto& stream : streams_) { |
| 1041 FFmpegDemuxerStream* stream = streams_[idx]; | 1039 if (!stream || stream->type() != DemuxerStream::TEXT) |
| 1042 if (stream == NULL || stream->type() != DemuxerStream::TEXT) | |
| 1043 continue; | 1040 continue; |
| 1044 | 1041 |
| 1045 TextKind kind = stream->GetTextKind(); | 1042 TextKind kind = stream->GetTextKind(); |
| 1046 std::string title = stream->GetMetadata("title"); | 1043 std::string title = stream->GetMetadata("title"); |
| 1047 std::string language = stream->GetMetadata("language"); | 1044 std::string language = stream->GetMetadata("language"); |
| 1048 | 1045 |
| 1049 // TODO: Implement "id" metadata in FFMPEG. | 1046 // TODO: Implement "id" metadata in FFMPEG. |
| 1050 // See: http://crbug.com/323183 | 1047 // See: http://crbug.com/323183 |
| 1051 host_->AddTextStream(stream, TextTrackConfig(kind, title, language, | 1048 host_->AddTextStream(stream.get(), |
| 1052 std::string())); | 1049 TextTrackConfig(kind, title, language, std::string())); |
| 1053 } | 1050 } |
| 1054 } | 1051 } |
| 1055 | 1052 |
| 1056 int64_t FFmpegDemuxer::GetMemoryUsage() const { | 1053 int64_t FFmpegDemuxer::GetMemoryUsage() const { |
| 1057 int64_t allocation_size = 0; | 1054 int64_t allocation_size = 0; |
| 1058 for (auto* stream : streams_) { | 1055 for (const auto& stream : streams_) { |
| 1059 if (stream) | 1056 if (stream) |
| 1060 allocation_size += stream->MemoryUsage(); | 1057 allocation_size += stream->MemoryUsage(); |
| 1061 } | 1058 } |
| 1062 return allocation_size; | 1059 return allocation_size; |
| 1063 } | 1060 } |
| 1064 | 1061 |
| 1065 void FFmpegDemuxer::OnEncryptedMediaInitData( | 1062 void FFmpegDemuxer::OnEncryptedMediaInitData( |
| 1066 EmeInitDataType init_data_type, | 1063 EmeInitDataType init_data_type, |
| 1067 const std::string& encryption_key_id) { | 1064 const std::string& encryption_key_id) { |
| 1068 std::vector<uint8_t> key_id_local(encryption_key_id.begin(), | 1065 std::vector<uint8_t> key_id_local(encryption_key_id.begin(), |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1198 const base::TimeDelta packet_pts = | 1195 const base::TimeDelta packet_pts = |
| 1199 ConvertFromTimeBase(stream->time_base, packet_buffer->pkt.pts); | 1196 ConvertFromTimeBase(stream->time_base, packet_buffer->pkt.pts); |
| 1200 if (packet_pts < start_time_estimates[stream->index]) | 1197 if (packet_pts < start_time_estimates[stream->index]) |
| 1201 start_time_estimates[stream->index] = packet_pts; | 1198 start_time_estimates[stream->index] = packet_pts; |
| 1202 } | 1199 } |
| 1203 packet_buffer = packet_buffer->next; | 1200 packet_buffer = packet_buffer->next; |
| 1204 } | 1201 } |
| 1205 } | 1202 } |
| 1206 | 1203 |
| 1207 std::unique_ptr<MediaTracks> media_tracks(new MediaTracks()); | 1204 std::unique_ptr<MediaTracks> media_tracks(new MediaTracks()); |
| 1208 AVStream* audio_stream = NULL; | |
| 1209 AudioDecoderConfig audio_config; | |
| 1210 AVStream* video_stream = NULL; | |
| 1211 VideoDecoderConfig video_config; | |
| 1212 | 1205 |
| 1213 DCHECK(track_id_to_demux_stream_map_.empty()); | 1206 DCHECK(track_id_to_demux_stream_map_.empty()); |
| 1214 | 1207 |
| 1215 // If available, |start_time_| will be set to the lowest stream start time. | 1208 // If available, |start_time_| will be set to the lowest stream start time. |
| 1216 start_time_ = kInfiniteDuration; | 1209 start_time_ = kInfiniteDuration; |
| 1217 | 1210 |
| 1218 base::TimeDelta max_duration; | 1211 base::TimeDelta max_duration; |
| 1219 int detected_audio_track_count = 0; | 1212 int detected_audio_track_count = 0; |
| 1220 int detected_video_track_count = 0; | 1213 int detected_video_track_count = 0; |
| 1221 int detected_text_track_count = 0; | 1214 int detected_text_track_count = 0; |
| 1222 for (size_t i = 0; i < format_context->nb_streams; ++i) { | 1215 for (size_t i = 0; i < format_context->nb_streams; ++i) { |
| 1223 AVStream* stream = format_context->streams[i]; | 1216 AVStream* stream = format_context->streams[i]; |
| 1224 const AVCodecContext* codec_context = stream->codec; | 1217 const AVCodecContext* codec_context = stream->codec; |
| 1225 const AVMediaType codec_type = codec_context->codec_type; | 1218 const AVMediaType codec_type = codec_context->codec_type; |
| 1226 | 1219 |
| 1227 if (codec_type == AVMEDIA_TYPE_AUDIO) { | 1220 if (codec_type == AVMEDIA_TYPE_AUDIO) { |
| 1228 // Log the codec detected, whether it is supported or not, and whether or | 1221 // Log the codec detected, whether it is supported or not, and whether or |
| 1229 // not we have already detected a supported codec in another stream. | 1222 // not we have already detected a supported codec in another stream. |
| 1230 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedAudioCodecHash", | 1223 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedAudioCodecHash", |
| 1231 HashCodecName(GetCodecName(codec_context))); | 1224 HashCodecName(GetCodecName(codec_context))); |
| 1232 detected_audio_track_count++; | 1225 detected_audio_track_count++; |
| 1233 | |
| 1234 if (audio_stream) { | |
| 1235 MEDIA_LOG(INFO, media_log_) << GetDisplayName() | |
| 1236 << ": skipping extra audio track"; | |
| 1237 continue; | |
| 1238 } | |
| 1239 } else if (codec_type == AVMEDIA_TYPE_VIDEO) { | 1226 } else if (codec_type == AVMEDIA_TYPE_VIDEO) { |
| 1240 // Log the codec detected, whether it is supported or not, and whether or | 1227 // Log the codec detected, whether it is supported or not, and whether or |
| 1241 // not we have already detected a supported codec in another stream. | 1228 // not we have already detected a supported codec in another stream. |
| 1242 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedVideoCodecHash", | 1229 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedVideoCodecHash", |
| 1243 HashCodecName(GetCodecName(codec_context))); | 1230 HashCodecName(GetCodecName(codec_context))); |
| 1244 detected_video_track_count++; | 1231 detected_video_track_count++; |
| 1245 | 1232 |
| 1246 if (video_stream) { | |
| 1247 MEDIA_LOG(INFO, media_log_) << GetDisplayName() | |
| 1248 << ": skipping extra video track"; | |
| 1249 continue; | |
| 1250 } | |
| 1251 | |
| 1252 #if BUILDFLAG(ENABLE_HEVC_DEMUXING) | 1233 #if BUILDFLAG(ENABLE_HEVC_DEMUXING) |
| 1253 if (stream->codec->codec_id == AV_CODEC_ID_HEVC) { | 1234 if (stream->codec->codec_id == AV_CODEC_ID_HEVC) { |
| 1254 // If ffmpeg is built without HEVC parser/decoder support, it will be | 1235 // If ffmpeg is built without HEVC parser/decoder support, it will be |
| 1255 // able to demux HEVC based solely on container-provided information, | 1236 // able to demux HEVC based solely on container-provided information, |
| 1256 // but unable to get some of the parameters without parsing the stream | 1237 // but unable to get some of the parameters without parsing the stream |
| 1257 // (e.g. coded size needs to be read from SPS, pixel format is typically | 1238 // (e.g. coded size needs to be read from SPS, pixel format is typically |
| 1258 // deduced from decoder config in hvcC box). These are not really needed | 1239 // deduced from decoder config in hvcC box). These are not really needed |
| 1259 // when using external decoder (e.g. hardware decoder), so override them | 1240 // when using external decoder (e.g. hardware decoder), so override them |
| 1260 // here, to make sure this translates into a valid VideoDecoderConfig. | 1241 // here, to make sure this translates into a valid VideoDecoderConfig. |
| 1261 if (stream->codec->coded_width == 0 && | 1242 if (stream->codec->coded_width == 0 && |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1278 } else { | 1259 } else { |
| 1279 continue; | 1260 continue; |
| 1280 } | 1261 } |
| 1281 | 1262 |
| 1282 // Attempt to create a FFmpegDemuxerStream from the AVStream. This will | 1263 // Attempt to create a FFmpegDemuxerStream from the AVStream. This will |
| 1283 // return nullptr if the AVStream is invalid. Validity checks will verify | 1264 // return nullptr if the AVStream is invalid. Validity checks will verify |
| 1284 // things like: codec, channel layout, sample/pixel format, etc... | 1265 // things like: codec, channel layout, sample/pixel format, etc... |
| 1285 std::unique_ptr<FFmpegDemuxerStream> demuxer_stream = | 1266 std::unique_ptr<FFmpegDemuxerStream> demuxer_stream = |
| 1286 FFmpegDemuxerStream::Create(this, stream, media_log_); | 1267 FFmpegDemuxerStream::Create(this, stream, media_log_); |
| 1287 if (demuxer_stream.get()) { | 1268 if (demuxer_stream.get()) { |
| 1288 streams_[i] = demuxer_stream.release(); | 1269 streams_[i] = std::move(demuxer_stream); |
| 1289 } else { | 1270 } else { |
| 1290 if (codec_type == AVMEDIA_TYPE_AUDIO) { | 1271 if (codec_type == AVMEDIA_TYPE_AUDIO) { |
| 1291 MEDIA_LOG(INFO, media_log_) | 1272 MEDIA_LOG(INFO, media_log_) |
| 1292 << GetDisplayName() | 1273 << GetDisplayName() |
| 1293 << ": skipping invalid or unsupported audio track"; | 1274 << ": skipping invalid or unsupported audio track"; |
| 1294 } else if (codec_type == AVMEDIA_TYPE_VIDEO) { | 1275 } else if (codec_type == AVMEDIA_TYPE_VIDEO) { |
| 1295 MEDIA_LOG(INFO, media_log_) | 1276 MEDIA_LOG(INFO, media_log_) |
| 1296 << GetDisplayName() | 1277 << GetDisplayName() |
| 1297 << ": skipping invalid or unsupported video track"; | 1278 << ": skipping invalid or unsupported video track"; |
| 1298 } | 1279 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1312 // Need to fix that and use it as track id. crbug.com/323183 | 1293 // Need to fix that and use it as track id. crbug.com/323183 |
| 1313 track_id = | 1294 track_id = |
| 1314 static_cast<StreamParser::TrackId>(media_tracks->tracks().size() + 1); | 1295 static_cast<StreamParser::TrackId>(media_tracks->tracks().size() + 1); |
| 1315 track_label = streams_[i]->GetMetadata("title"); | 1296 track_label = streams_[i]->GetMetadata("title"); |
| 1316 } | 1297 } |
| 1317 | 1298 |
| 1318 // Note when we find our audio/video stream (we only want one of each) and | 1299 // Note when we find our audio/video stream (we only want one of each) and |
| 1319 // record src= playback UMA stats for the stream's decoder config. | 1300 // record src= playback UMA stats for the stream's decoder config. |
| 1320 MediaTrack* media_track = nullptr; | 1301 MediaTrack* media_track = nullptr; |
| 1321 if (codec_type == AVMEDIA_TYPE_AUDIO) { | 1302 if (codec_type == AVMEDIA_TYPE_AUDIO) { |
| 1322 CHECK(!audio_stream); | 1303 AudioDecoderConfig audio_config = streams_[i]->audio_decoder_config(); |
| 1323 audio_stream = stream; | |
| 1324 audio_config = streams_[i]->audio_decoder_config(); | |
| 1325 RecordAudioCodecStats(audio_config); | 1304 RecordAudioCodecStats(audio_config); |
| 1326 | 1305 |
| 1327 media_track = media_tracks->AddAudioTrack(audio_config, track_id, "main", | 1306 media_track = media_tracks->AddAudioTrack(audio_config, track_id, "main", |
| 1328 track_label, track_language); | 1307 track_label, track_language); |
| 1329 media_track->set_id(base::UintToString(track_id)); | 1308 media_track->set_id(base::UintToString(track_id)); |
| 1330 DCHECK(track_id_to_demux_stream_map_.find(media_track->id()) == | 1309 DCHECK(track_id_to_demux_stream_map_.find(media_track->id()) == |
| 1331 track_id_to_demux_stream_map_.end()); | 1310 track_id_to_demux_stream_map_.end()); |
| 1332 track_id_to_demux_stream_map_[media_track->id()] = streams_[i]; | 1311 track_id_to_demux_stream_map_[media_track->id()] = streams_[i].get(); |
| 1333 } else if (codec_type == AVMEDIA_TYPE_VIDEO) { | 1312 } else if (codec_type == AVMEDIA_TYPE_VIDEO) { |
| 1334 CHECK(!video_stream); | 1313 VideoDecoderConfig video_config = streams_[i]->video_decoder_config(); |
| 1335 video_stream = stream; | |
| 1336 video_config = streams_[i]->video_decoder_config(); | |
| 1337 | 1314 |
| 1338 RecordVideoCodecStats(video_config, stream->codec->color_range, | 1315 RecordVideoCodecStats(video_config, stream->codec->color_range, |
| 1339 media_log_.get()); | 1316 media_log_.get()); |
| 1340 | 1317 |
| 1341 media_track = media_tracks->AddVideoTrack(video_config, track_id, "main", | 1318 media_track = media_tracks->AddVideoTrack(video_config, track_id, "main", |
| 1342 track_label, track_language); | 1319 track_label, track_language); |
| 1343 media_track->set_id(base::UintToString(track_id)); | 1320 media_track->set_id(base::UintToString(track_id)); |
| 1344 DCHECK(track_id_to_demux_stream_map_.find(media_track->id()) == | 1321 DCHECK(track_id_to_demux_stream_map_.find(media_track->id()) == |
| 1345 track_id_to_demux_stream_map_.end()); | 1322 track_id_to_demux_stream_map_.end()); |
| 1346 track_id_to_demux_stream_map_[media_track->id()] = streams_[i]; | 1323 track_id_to_demux_stream_map_[media_track->id()] = streams_[i].get(); |
| 1347 } | 1324 } |
| 1348 | 1325 |
| 1349 max_duration = std::max(max_duration, streams_[i]->duration()); | 1326 max_duration = std::max(max_duration, streams_[i]->duration()); |
| 1350 | 1327 |
| 1351 const base::TimeDelta start_time = | 1328 const base::TimeDelta start_time = |
| 1352 ExtractStartTime(stream, start_time_estimates[i]); | 1329 ExtractStartTime(stream, start_time_estimates[i]); |
| 1353 const bool has_start_time = start_time != kNoTimestamp; | 1330 const bool has_start_time = start_time != kNoTimestamp; |
| 1354 | 1331 |
| 1355 if (!has_start_time) | 1332 if (!has_start_time) |
| 1356 continue; | 1333 continue; |
| 1357 | 1334 |
| 1358 streams_[i]->set_start_time(start_time); | 1335 streams_[i]->set_start_time(start_time); |
| 1359 if (start_time < start_time_) { | 1336 if (start_time < start_time_) { |
| 1360 start_time_ = start_time; | 1337 start_time_ = start_time; |
| 1361 } | 1338 } |
| 1362 } | 1339 } |
| 1363 | 1340 |
| 1364 RecordDetectedTrackTypeStats(detected_audio_track_count, | 1341 RecordDetectedTrackTypeStats(detected_audio_track_count, |
| 1365 detected_video_track_count, | 1342 detected_video_track_count, |
| 1366 detected_text_track_count); | 1343 detected_text_track_count); |
| 1367 | 1344 |
| 1368 if (!audio_stream && !video_stream) { | 1345 if (media_tracks->tracks().empty()) { |
| 1369 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() | 1346 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() |
| 1370 << ": no supported streams"; | 1347 << ": no supported streams"; |
| 1371 status_cb.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); | 1348 status_cb.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); |
| 1372 return; | 1349 return; |
| 1373 } | 1350 } |
| 1374 | 1351 |
| 1375 if (text_enabled_) | 1352 if (text_enabled_) |
| 1376 AddTextStreams(); | 1353 AddTextStreams(); |
| 1377 | 1354 |
| 1378 if (format_context->duration != static_cast<int64_t>(AV_NOPTS_VALUE)) { | 1355 if (format_context->duration != static_cast<int64_t>(AV_NOPTS_VALUE)) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1396 // not be exposed to negative timestamps. Which means we need to rebase these | 1373 // not be exposed to negative timestamps. Which means we need to rebase these |
| 1397 // negative timestamps and mark them for discard post decoding. | 1374 // negative timestamps and mark them for discard post decoding. |
| 1398 // | 1375 // |
| 1399 // Post-decode frame dropping for packets with negative timestamps is outlined | 1376 // Post-decode frame dropping for packets with negative timestamps is outlined |
| 1400 // in section A.2 in the Ogg Vorbis spec: | 1377 // in section A.2 in the Ogg Vorbis spec: |
| 1401 // http://xiph.org/vorbis/doc/Vorbis_I_spec.html | 1378 // http://xiph.org/vorbis/doc/Vorbis_I_spec.html |
| 1402 // | 1379 // |
| 1403 // FFmpeg's use of negative timestamps for opus pre-skip is nonstandard, but | 1380 // FFmpeg's use of negative timestamps for opus pre-skip is nonstandard, but |
| 1404 // for more information on pre-skip see section 4.2 of the Ogg Opus spec: | 1381 // for more information on pre-skip see section 4.2 of the Ogg Opus spec: |
| 1405 // https://tools.ietf.org/html/draft-ietf-codec-oggopus-08#section-4.2 | 1382 // https://tools.ietf.org/html/draft-ietf-codec-oggopus-08#section-4.2 |
| 1406 if (audio_stream && (audio_stream->codec->codec_id == AV_CODEC_ID_OPUS || | 1383 for (const auto& stream : streams_) { |
| 1407 (strcmp(format_context->iformat->name, "ogg") == 0 && | 1384 if (!stream || stream->type() != DemuxerStream::AUDIO) |
| 1408 audio_stream->codec->codec_id == AV_CODEC_ID_VORBIS))) { | 1385 continue; |
| 1409 for (size_t i = 0; i < streams_.size(); ++i) { | 1386 const AVStream* audio_stream = stream->av_stream(); |
| 1410 if (!streams_[i]) | 1387 DCHECK(audio_stream); |
| 1411 continue; | 1388 if (audio_stream->codec->codec_id == AV_CODEC_ID_OPUS || |
| 1412 streams_[i]->enable_negative_timestamp_fixups(); | 1389 (strcmp(format_context->iformat->name, "ogg") == 0 && |
| 1390 audio_stream->codec->codec_id == AV_CODEC_ID_VORBIS)) { |
| 1391 for (size_t i = 0; i < streams_.size(); ++i) { |
| 1392 if (!streams_[i]) |
| 1393 continue; |
| 1394 streams_[i]->enable_negative_timestamp_fixups(); |
| 1413 | 1395 |
| 1414 // Fixup the seeking information to avoid selecting the audio stream | 1396 // Fixup the seeking information to avoid selecting the audio stream |
| 1415 // simply because it has a lower starting time. | 1397 // simply because it has a lower starting time. |
| 1416 if (streams_[i]->av_stream() == audio_stream && | 1398 if (streams_[i]->av_stream() == audio_stream && |
| 1417 streams_[i]->start_time() < base::TimeDelta()) { | 1399 streams_[i]->start_time() < base::TimeDelta()) { |
| 1418 streams_[i]->set_start_time(base::TimeDelta()); | 1400 streams_[i]->set_start_time(base::TimeDelta()); |
| 1401 } |
| 1419 } | 1402 } |
| 1420 } | 1403 } |
| 1421 } | 1404 } |
| 1422 | 1405 |
| 1423 // If no start time could be determined, default to zero. | 1406 // If no start time could be determined, default to zero. |
| 1424 if (start_time_ == kInfiniteDuration) { | 1407 if (start_time_ == kInfiniteDuration) { |
| 1425 start_time_ = base::TimeDelta(); | 1408 start_time_ = base::TimeDelta(); |
| 1426 } | 1409 } |
| 1427 | 1410 |
| 1428 // MPEG-4 B-frames cause grief for a simple container like AVI. Enable PTS | 1411 // MPEG-4 B-frames cause grief for a simple container like AVI. Enable PTS |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1451 // initializing. | 1434 // initializing. |
| 1452 host_->SetDuration(max_duration); | 1435 host_->SetDuration(max_duration); |
| 1453 duration_known_ = (max_duration != kInfiniteDuration); | 1436 duration_known_ = (max_duration != kInfiniteDuration); |
| 1454 | 1437 |
| 1455 int64_t filesize_in_bytes = 0; | 1438 int64_t filesize_in_bytes = 0; |
| 1456 url_protocol_->GetSize(&filesize_in_bytes); | 1439 url_protocol_->GetSize(&filesize_in_bytes); |
| 1457 bitrate_ = CalculateBitrate(format_context, max_duration, filesize_in_bytes); | 1440 bitrate_ = CalculateBitrate(format_context, max_duration, filesize_in_bytes); |
| 1458 if (bitrate_ > 0) | 1441 if (bitrate_ > 0) |
| 1459 data_source_->SetBitrate(bitrate_); | 1442 data_source_->SetBitrate(bitrate_); |
| 1460 | 1443 |
| 1444 LogMetadata(format_context, max_duration); |
| 1445 media_tracks_updated_cb_.Run(std::move(media_tracks)); |
| 1446 |
| 1447 status_cb.Run(PIPELINE_OK); |
| 1448 } |
| 1449 |
| 1450 void FFmpegDemuxer::LogMetadata(AVFormatContext* avctx, |
| 1451 base::TimeDelta max_duration) { |
| 1461 // Use a single MediaLogEvent to batch all parameter updates at once; this | 1452 // Use a single MediaLogEvent to batch all parameter updates at once; this |
| 1462 // prevents throttling of events due to the large number of updates here. | 1453 // prevents throttling of events due to the large number of updates here. |
| 1463 std::unique_ptr<MediaLogEvent> metadata_event = | 1454 std::unique_ptr<MediaLogEvent> metadata_event = |
| 1464 media_log_->CreateEvent(MediaLogEvent::PROPERTY_CHANGE); | 1455 media_log_->CreateEvent(MediaLogEvent::PROPERTY_CHANGE); |
| 1465 | 1456 |
| 1466 // Audio logging. | 1457 DCHECK_EQ(avctx->nb_streams, streams_.size()); |
| 1467 metadata_event->params.SetBoolean("found_audio_stream", !!audio_stream); | 1458 auto& params = metadata_event->params; |
| 1468 if (audio_stream) { | 1459 int audio_track_count = 0; |
| 1469 const AVCodecContext* audio_codec = audio_stream->codec; | 1460 int video_track_count = 0; |
| 1470 metadata_event->params.SetString("audio_codec_name", | 1461 for (size_t i = 0; i < streams_.size(); ++i) { |
| 1471 GetCodecName(audio_codec)); | 1462 FFmpegDemuxerStream* stream = streams_[i].get(); |
| 1472 metadata_event->params.SetInteger("audio_channels_count", | 1463 if (!stream) |
| 1473 audio_codec->channels); | 1464 continue; |
| 1474 metadata_event->params.SetString( | 1465 if (stream->type() == DemuxerStream::AUDIO) { |
| 1475 "audio_sample_format", | 1466 ++audio_track_count; |
| 1476 SampleFormatToString(audio_config.sample_format())); | 1467 std::string suffix = ""; |
| 1477 metadata_event->params.SetInteger("audio_samples_per_second", | 1468 if (audio_track_count > 1) |
| 1478 audio_config.samples_per_second()); | 1469 suffix = "_track" + base::IntToString(audio_track_count); |
| 1470 const AVCodecContext* audio_codec = avctx->streams[i]->codec; |
| 1471 const AudioDecoderConfig& audio_config = stream->audio_decoder_config(); |
| 1472 params.SetString("audio_codec_name" + suffix, GetCodecName(audio_codec)); |
| 1473 params.SetInteger("audio_channels_count" + suffix, audio_codec->channels); |
| 1474 params.SetString("audio_sample_format" + suffix, |
| 1475 SampleFormatToString(audio_config.sample_format())); |
| 1476 params.SetInteger("audio_samples_per_second" + suffix, |
| 1477 audio_config.samples_per_second()); |
| 1478 } else if (stream->type() == DemuxerStream::VIDEO) { |
| 1479 ++video_track_count; |
| 1480 std::string suffix = ""; |
| 1481 if (video_track_count > 1) |
| 1482 suffix = "_track" + base::IntToString(video_track_count); |
| 1483 const AVCodecContext* video_codec = avctx->streams[i]->codec; |
| 1484 const VideoDecoderConfig& video_config = stream->video_decoder_config(); |
| 1485 params.SetString("video_codec_name" + suffix, GetCodecName(video_codec)); |
| 1486 params.SetInteger("width" + suffix, video_codec->width); |
| 1487 params.SetInteger("height" + suffix, video_codec->height); |
| 1488 params.SetInteger("coded_width" + suffix, video_codec->coded_width); |
| 1489 params.SetInteger("coded_height" + suffix, video_codec->coded_height); |
| 1490 params.SetString("time_base" + suffix, |
| 1491 base::StringPrintf("%d/%d", video_codec->time_base.num, |
| 1492 video_codec->time_base.den)); |
| 1493 params.SetString("video_format" + suffix, |
| 1494 VideoPixelFormatToString(video_config.format())); |
| 1495 params.SetBoolean("video_is_encrypted" + suffix, |
| 1496 video_config.is_encrypted()); |
| 1497 } |
| 1479 } | 1498 } |
| 1480 | 1499 params.SetBoolean("found_audio_stream", (audio_track_count > 0)); |
| 1481 // Video logging | 1500 params.SetBoolean("found_video_stream", (video_track_count > 0)); |
| 1482 metadata_event->params.SetBoolean("found_video_stream", !!video_stream); | |
| 1483 if (video_stream) { | |
| 1484 const AVCodecContext* video_codec = video_stream->codec; | |
| 1485 metadata_event->params.SetString("video_codec_name", | |
| 1486 GetCodecName(video_codec)); | |
| 1487 metadata_event->params.SetInteger("width", video_codec->width); | |
| 1488 metadata_event->params.SetInteger("height", video_codec->height); | |
| 1489 metadata_event->params.SetInteger("coded_width", video_codec->coded_width); | |
| 1490 metadata_event->params.SetInteger("coded_height", | |
| 1491 video_codec->coded_height); | |
| 1492 metadata_event->params.SetString( | |
| 1493 "time_base", base::StringPrintf("%d/%d", video_codec->time_base.num, | |
| 1494 video_codec->time_base.den)); | |
| 1495 metadata_event->params.SetString( | |
| 1496 "video_format", VideoPixelFormatToString(video_config.format())); | |
| 1497 metadata_event->params.SetBoolean("video_is_encrypted", | |
| 1498 video_config.is_encrypted()); | |
| 1499 } | |
| 1500 | |
| 1501 SetTimeProperty(metadata_event.get(), "max_duration", max_duration); | 1501 SetTimeProperty(metadata_event.get(), "max_duration", max_duration); |
| 1502 SetTimeProperty(metadata_event.get(), "start_time", start_time_); | 1502 SetTimeProperty(metadata_event.get(), "start_time", start_time_); |
| 1503 metadata_event->params.SetInteger("bitrate", bitrate_); | 1503 metadata_event->params.SetInteger("bitrate", bitrate_); |
| 1504 media_log_->AddEvent(std::move(metadata_event)); | 1504 media_log_->AddEvent(std::move(metadata_event)); |
| 1505 | |
| 1506 media_tracks_updated_cb_.Run(std::move(media_tracks)); | |
| 1507 | |
| 1508 status_cb.Run(PIPELINE_OK); | |
| 1509 } | 1505 } |
| 1510 | 1506 |
| 1511 FFmpegDemuxerStream* FFmpegDemuxer::FindPreferredStreamForSeeking( | 1507 FFmpegDemuxerStream* FFmpegDemuxer::FindPreferredStreamForSeeking( |
| 1512 base::TimeDelta seek_time) { | 1508 base::TimeDelta seek_time) { |
| 1513 // If we have a selected/enabled video stream and its start time is lower | 1509 // If we have a selected/enabled video stream and its start time is lower |
| 1514 // than the |seek_time| or unknown, then always prefer it for seeking. | 1510 // than the |seek_time| or unknown, then always prefer it for seeking. |
| 1515 FFmpegDemuxerStream* video_stream = nullptr; | 1511 FFmpegDemuxerStream* video_stream = nullptr; |
| 1516 for (const auto& stream : streams_) { | 1512 for (const auto& stream : streams_) { |
| 1517 if (stream && stream->type() == DemuxerStream::VIDEO && stream->enabled()) { | 1513 if (stream && stream->type() == DemuxerStream::VIDEO && stream->enabled()) { |
| 1518 video_stream = stream; | 1514 video_stream = stream.get(); |
| 1519 if (video_stream->start_time() == kNoTimestamp || | 1515 if (video_stream->start_time() == kNoTimestamp || |
| 1520 video_stream->start_time() <= seek_time) { | 1516 video_stream->start_time() <= seek_time) { |
| 1521 return stream; | 1517 return video_stream; |
| 1522 } | 1518 } |
| 1523 break; | 1519 break; |
| 1524 } | 1520 } |
| 1525 } | 1521 } |
| 1526 | 1522 |
| 1527 // If video stream is not present or |seek_time| is lower than the video start | 1523 // If video stream is not present or |seek_time| is lower than the video start |
| 1528 // time, then try to find an enabled stream with the lowest start time. | 1524 // time, then try to find an enabled stream with the lowest start time. |
| 1529 FFmpegDemuxerStream* lowest_start_time_stream = nullptr; | 1525 FFmpegDemuxerStream* lowest_start_time_stream = nullptr; |
| 1530 for (const auto& stream : streams_) { | 1526 for (const auto& stream : streams_) { |
| 1531 if (!stream || !stream->enabled() || stream->start_time() == kNoTimestamp) | 1527 if (!stream || !stream->enabled() || stream->start_time() == kNoTimestamp) |
| 1532 continue; | 1528 continue; |
| 1533 if (!lowest_start_time_stream || | 1529 if (!lowest_start_time_stream || |
| 1534 stream->start_time() < lowest_start_time_stream->start_time()) { | 1530 stream->start_time() < lowest_start_time_stream->start_time()) { |
| 1535 lowest_start_time_stream = stream; | 1531 lowest_start_time_stream = stream.get(); |
| 1536 } | 1532 } |
| 1537 } | 1533 } |
| 1538 // If we found a stream with start time lower than |seek_time|, then use it. | 1534 // If we found a stream with start time lower than |seek_time|, then use it. |
| 1539 if (lowest_start_time_stream && | 1535 if (lowest_start_time_stream && |
| 1540 lowest_start_time_stream->start_time() <= seek_time) { | 1536 lowest_start_time_stream->start_time() <= seek_time) { |
| 1541 return lowest_start_time_stream; | 1537 return lowest_start_time_stream; |
| 1542 } | 1538 } |
| 1543 | 1539 |
| 1544 // If we couldn't find any streams with the start time lower than |seek_time| | 1540 // If we couldn't find any streams with the start time lower than |seek_time| |
| 1545 // then use either video (if one exists) or any audio stream. | 1541 // then use either video (if one exists) or any audio stream. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1558 } | 1554 } |
| 1559 | 1555 |
| 1560 if (result < 0) { | 1556 if (result < 0) { |
| 1561 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being | 1557 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being |
| 1562 // captured from stdout and contaminates testing. | 1558 // captured from stdout and contaminates testing. |
| 1563 // TODO(scherkus): Implement this properly and signal error (BUG=23447). | 1559 // TODO(scherkus): Implement this properly and signal error (BUG=23447). |
| 1564 VLOG(1) << "Not implemented"; | 1560 VLOG(1) << "Not implemented"; |
| 1565 } | 1561 } |
| 1566 | 1562 |
| 1567 // Tell streams to flush buffers due to seeking. | 1563 // Tell streams to flush buffers due to seeking. |
| 1568 StreamVector::iterator iter; | 1564 for (const auto& stream : streams_) { |
| 1569 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 1565 if (stream) |
| 1570 if (*iter) | 1566 stream->FlushBuffers(); |
| 1571 (*iter)->FlushBuffers(); | |
| 1572 } | 1567 } |
| 1573 | 1568 |
| 1574 // Resume reading until capacity. | 1569 // Resume reading until capacity. |
| 1575 ReadFrameIfNeeded(); | 1570 ReadFrameIfNeeded(); |
| 1576 | 1571 |
| 1577 // Notify we're finished seeking. | 1572 // Notify we're finished seeking. |
| 1578 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_OK); | 1573 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_OK); |
| 1579 } | 1574 } |
| 1580 | 1575 |
| 1581 void FFmpegDemuxer::OnEnabledAudioTracksChanged( | 1576 void FFmpegDemuxer::OnEnabledAudioTracksChanged( |
| 1582 const std::vector<MediaTrack::Id>& track_ids, | 1577 const std::vector<MediaTrack::Id>& track_ids, |
| 1583 base::TimeDelta currTime) { | 1578 base::TimeDelta currTime) { |
| 1584 DCHECK(task_runner_->BelongsToCurrentThread()); | 1579 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1585 bool enabled = false; | 1580 |
| 1586 DemuxerStream* audio_stream = GetStream(DemuxerStream::AUDIO); | 1581 std::set<DemuxerStream*> enabled_streams; |
| 1587 CHECK(audio_stream); | 1582 for (const auto& id : track_ids) { |
| 1588 if (track_ids.size() > 0) { | 1583 DemuxerStream* stream = track_id_to_demux_stream_map_[id]; |
| 1589 DCHECK(track_id_to_demux_stream_map_[track_ids[0]] == audio_stream); | 1584 DCHECK(stream); |
| 1590 enabled = true; | 1585 DCHECK_EQ(DemuxerStream::AUDIO, stream->type()); |
| 1586 enabled_streams.insert(stream); |
| 1591 } | 1587 } |
| 1592 DVLOG(1) << __func__ << ": " << (enabled ? "enabling" : "disabling") | 1588 |
| 1593 << " audio stream"; | 1589 // First disable all streams that need to be disabled and then enable streams |
| 1594 audio_stream->set_enabled(enabled, currTime); | 1590 // that are enabled. |
| 1591 for (const auto& stream : streams_) { |
| 1592 if (stream->type() == DemuxerStream::AUDIO && |
| 1593 enabled_streams.find(stream.get()) == enabled_streams.end()) { |
| 1594 DVLOG(1) << __func__ << ": disabling stream " << stream.get(); |
| 1595 stream->set_enabled(false, currTime); |
| 1596 } |
| 1597 } |
| 1598 for (const auto& stream : enabled_streams) { |
| 1599 DVLOG(1) << __func__ << ": enabling stream " << stream; |
| 1600 stream->set_enabled(true, currTime); |
| 1601 } |
| 1595 } | 1602 } |
| 1596 | 1603 |
| 1597 void FFmpegDemuxer::OnSelectedVideoTrackChanged( | 1604 void FFmpegDemuxer::OnSelectedVideoTrackChanged( |
| 1598 const std::vector<MediaTrack::Id>& track_ids, | 1605 const std::vector<MediaTrack::Id>& track_ids, |
| 1599 base::TimeDelta currTime) { | 1606 base::TimeDelta currTime) { |
| 1600 DCHECK(task_runner_->BelongsToCurrentThread()); | 1607 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1601 bool enabled = false; | 1608 DCHECK_LE(track_ids.size(), 1u); |
| 1602 DemuxerStream* video_stream = GetStream(DemuxerStream::VIDEO); | 1609 |
| 1603 CHECK(video_stream); | 1610 DemuxerStream* selected_stream = nullptr; |
| 1604 if (track_ids.size() > 0) { | 1611 if (!track_ids.empty()) { |
| 1605 DCHECK(track_id_to_demux_stream_map_[track_ids[0]] == video_stream); | 1612 selected_stream = track_id_to_demux_stream_map_[track_ids[0]]; |
| 1606 enabled = true; | 1613 DCHECK(selected_stream); |
| 1614 DCHECK_EQ(DemuxerStream::VIDEO, selected_stream->type()); |
| 1607 } | 1615 } |
| 1608 DVLOG(1) << __func__ << ": " << (enabled ? "enabling" : "disabling") | 1616 |
| 1609 << " video stream"; | 1617 // First disable all streams that need to be disabled and then enable the |
| 1610 video_stream->set_enabled(enabled, currTime); | 1618 // stream that needs to be enabled (if any). |
| 1619 for (const auto& stream : streams_) { |
| 1620 if (stream->type() == DemuxerStream::VIDEO && |
| 1621 stream.get() != selected_stream) { |
| 1622 DVLOG(1) << __func__ << ": disabling stream " << stream.get(); |
| 1623 stream->set_enabled(false, currTime); |
| 1624 } |
| 1625 } |
| 1626 if (selected_stream) { |
| 1627 DVLOG(1) << __func__ << ": enabling stream " << selected_stream; |
| 1628 selected_stream->set_enabled(true, currTime); |
| 1629 } |
| 1611 } | 1630 } |
| 1612 | 1631 |
| 1613 void FFmpegDemuxer::ReadFrameIfNeeded() { | 1632 void FFmpegDemuxer::ReadFrameIfNeeded() { |
| 1614 DCHECK(task_runner_->BelongsToCurrentThread()); | 1633 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1615 | 1634 |
| 1616 // Make sure we have work to do before reading. | 1635 // Make sure we have work to do before reading. |
| 1617 if (!blocking_thread_.IsRunning() || !StreamsHaveAvailableCapacity() || | 1636 if (!blocking_thread_.IsRunning() || !StreamsHaveAvailableCapacity() || |
| 1618 pending_read_ || !pending_seek_cb_.is_null()) { | 1637 pending_read_ || !pending_seek_cb_.is_null()) { |
| 1619 return; | 1638 return; |
| 1620 } | 1639 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1647 // - either underlying ffmpeg returned an error | 1666 // - either underlying ffmpeg returned an error |
| 1648 // - or FFMpegDemuxer reached the maximum allowed memory usage. | 1667 // - or FFMpegDemuxer reached the maximum allowed memory usage. |
| 1649 if (result < 0 || IsMaxMemoryUsageReached()) { | 1668 if (result < 0 || IsMaxMemoryUsageReached()) { |
| 1650 DVLOG(1) << __func__ << " result=" << result | 1669 DVLOG(1) << __func__ << " result=" << result |
| 1651 << " IsMaxMemoryUsageReached=" << IsMaxMemoryUsageReached(); | 1670 << " IsMaxMemoryUsageReached=" << IsMaxMemoryUsageReached(); |
| 1652 // Update the duration based on the highest elapsed time across all streams | 1671 // Update the duration based on the highest elapsed time across all streams |
| 1653 // if it was previously unknown. | 1672 // if it was previously unknown. |
| 1654 if (!duration_known_) { | 1673 if (!duration_known_) { |
| 1655 base::TimeDelta max_duration; | 1674 base::TimeDelta max_duration; |
| 1656 | 1675 |
| 1657 for (StreamVector::iterator iter = streams_.begin(); | 1676 for (const auto& stream : streams_) { |
| 1658 iter != streams_.end(); | 1677 if (!stream) |
| 1659 ++iter) { | |
| 1660 if (!*iter) | |
| 1661 continue; | 1678 continue; |
| 1662 | 1679 |
| 1663 base::TimeDelta duration = (*iter)->GetElapsedTime(); | 1680 base::TimeDelta duration = stream->GetElapsedTime(); |
| 1664 if (duration != kNoTimestamp && duration > max_duration) | 1681 if (duration != kNoTimestamp && duration > max_duration) |
| 1665 max_duration = duration; | 1682 max_duration = duration; |
| 1666 } | 1683 } |
| 1667 | 1684 |
| 1668 if (max_duration > base::TimeDelta()) { | 1685 if (max_duration > base::TimeDelta()) { |
| 1669 host_->SetDuration(max_duration); | 1686 host_->SetDuration(max_duration); |
| 1670 duration_known_ = true; | 1687 duration_known_ = true; |
| 1671 } | 1688 } |
| 1672 } | 1689 } |
| 1673 // If we have reached the end of stream, tell the downstream filters about | 1690 // If we have reached the end of stream, tell the downstream filters about |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1688 // when av_read_frame() returns success code. See bug comment for ideas: | 1705 // when av_read_frame() returns success code. See bug comment for ideas: |
| 1689 // | 1706 // |
| 1690 // https://code.google.com/p/chromium/issues/detail?id=169133#c10 | 1707 // https://code.google.com/p/chromium/issues/detail?id=169133#c10 |
| 1691 if (!packet->data) { | 1708 if (!packet->data) { |
| 1692 ScopedAVPacket new_packet(new AVPacket()); | 1709 ScopedAVPacket new_packet(new AVPacket()); |
| 1693 av_new_packet(new_packet.get(), 0); | 1710 av_new_packet(new_packet.get(), 0); |
| 1694 av_packet_copy_props(new_packet.get(), packet.get()); | 1711 av_packet_copy_props(new_packet.get(), packet.get()); |
| 1695 packet.swap(new_packet); | 1712 packet.swap(new_packet); |
| 1696 } | 1713 } |
| 1697 | 1714 |
| 1698 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index]; | 1715 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index].get(); |
| 1699 if (demuxer_stream->enabled()) | 1716 if (demuxer_stream->enabled()) |
| 1700 demuxer_stream->EnqueuePacket(std::move(packet)); | 1717 demuxer_stream->EnqueuePacket(std::move(packet)); |
| 1701 } | 1718 } |
| 1702 | 1719 |
| 1703 // Keep reading until we've reached capacity. | 1720 // Keep reading until we've reached capacity. |
| 1704 ReadFrameIfNeeded(); | 1721 ReadFrameIfNeeded(); |
| 1705 } | 1722 } |
| 1706 | 1723 |
| 1707 bool FFmpegDemuxer::StreamsHaveAvailableCapacity() { | 1724 bool FFmpegDemuxer::StreamsHaveAvailableCapacity() { |
| 1708 DCHECK(task_runner_->BelongsToCurrentThread()); | 1725 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1709 StreamVector::iterator iter; | 1726 for (const auto& stream : streams_) { |
| 1710 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 1727 if (stream && stream->HasAvailableCapacity()) |
| 1711 if (*iter && (*iter)->HasAvailableCapacity()) { | |
| 1712 return true; | 1728 return true; |
| 1713 } | |
| 1714 } | 1729 } |
| 1715 return false; | 1730 return false; |
| 1716 } | 1731 } |
| 1717 | 1732 |
| 1718 bool FFmpegDemuxer::IsMaxMemoryUsageReached() const { | 1733 bool FFmpegDemuxer::IsMaxMemoryUsageReached() const { |
| 1719 DCHECK(task_runner_->BelongsToCurrentThread()); | 1734 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1720 | 1735 |
| 1721 // Max allowed memory usage, all streams combined. | 1736 // Max allowed memory usage, all streams combined. |
| 1722 const size_t kDemuxerMemoryLimit = 150 * 1024 * 1024; | 1737 const size_t kDemuxerMemoryLimit = 150 * 1024 * 1024; |
| 1723 | 1738 |
| 1724 size_t memory_left = kDemuxerMemoryLimit; | 1739 size_t memory_left = kDemuxerMemoryLimit; |
| 1725 for (StreamVector::const_iterator iter = streams_.begin(); | 1740 for (const auto& stream : streams_) { |
| 1726 iter != streams_.end(); ++iter) { | 1741 if (!stream) |
| 1727 if (!(*iter)) | |
| 1728 continue; | 1742 continue; |
| 1729 | 1743 |
| 1730 size_t stream_memory_usage = (*iter)->MemoryUsage(); | 1744 size_t stream_memory_usage = stream->MemoryUsage(); |
| 1731 if (stream_memory_usage > memory_left) | 1745 if (stream_memory_usage > memory_left) |
| 1732 return true; | 1746 return true; |
| 1733 memory_left -= stream_memory_usage; | 1747 memory_left -= stream_memory_usage; |
| 1734 } | 1748 } |
| 1735 return false; | 1749 return false; |
| 1736 } | 1750 } |
| 1737 | 1751 |
| 1738 void FFmpegDemuxer::StreamHasEnded() { | 1752 void FFmpegDemuxer::StreamHasEnded() { |
| 1739 DCHECK(task_runner_->BelongsToCurrentThread()); | 1753 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1740 StreamVector::iterator iter; | 1754 for (const auto& stream : streams_) { |
| 1741 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 1755 if (stream) |
| 1742 if (!*iter) | 1756 stream->SetEndOfStream(); |
| 1743 continue; | |
| 1744 (*iter)->SetEndOfStream(); | |
| 1745 } | 1757 } |
| 1746 } | 1758 } |
| 1747 | 1759 |
| 1748 void FFmpegDemuxer::OnDataSourceError() { | 1760 void FFmpegDemuxer::OnDataSourceError() { |
| 1749 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": data source error"; | 1761 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": data source error"; |
| 1750 host_->OnDemuxerError(PIPELINE_ERROR_READ); | 1762 host_->OnDemuxerError(PIPELINE_ERROR_READ); |
| 1751 } | 1763 } |
| 1752 | 1764 |
| 1753 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { | 1765 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { |
| 1754 DCHECK(task_runner_->BelongsToCurrentThread()); | 1766 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1755 for (auto* stream : streams_) { | 1767 for (const auto& stream : streams_) { |
| 1756 if (stream) | 1768 if (stream) |
| 1757 stream->SetLiveness(liveness); | 1769 stream->SetLiveness(liveness); |
| 1758 } | 1770 } |
| 1759 } | 1771 } |
| 1760 | 1772 |
| 1761 } // namespace media | 1773 } // namespace media |
| OLD | NEW |