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 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
257 // FFmpegDemuxerStream | 257 // FFmpegDemuxerStream |
258 // | 258 // |
259 FFmpegDemuxerStream::FFmpegDemuxerStream( | 259 FFmpegDemuxerStream::FFmpegDemuxerStream( |
260 FFmpegDemuxer* demuxer, | 260 FFmpegDemuxer* demuxer, |
261 AVStream* stream, | 261 AVStream* stream, |
262 std::unique_ptr<AudioDecoderConfig> audio_config, | 262 std::unique_ptr<AudioDecoderConfig> audio_config, |
263 std::unique_ptr<VideoDecoderConfig> video_config) | 263 std::unique_ptr<VideoDecoderConfig> video_config) |
264 : demuxer_(demuxer), | 264 : demuxer_(demuxer), |
265 task_runner_(base::ThreadTaskRunnerHandle::Get()), | 265 task_runner_(base::ThreadTaskRunnerHandle::Get()), |
266 stream_(stream), | 266 stream_(stream), |
267 start_time_(kNoTimestamp), | |
267 audio_config_(audio_config.release()), | 268 audio_config_(audio_config.release()), |
268 video_config_(video_config.release()), | 269 video_config_(video_config.release()), |
269 type_(UNKNOWN), | 270 type_(UNKNOWN), |
270 liveness_(LIVENESS_UNKNOWN), | 271 liveness_(LIVENESS_UNKNOWN), |
271 end_of_stream_(false), | 272 end_of_stream_(false), |
272 last_packet_timestamp_(kNoTimestamp), | 273 last_packet_timestamp_(kNoTimestamp), |
273 last_packet_duration_(kNoTimestamp), | 274 last_packet_duration_(kNoTimestamp), |
274 video_rotation_(VIDEO_ROTATION_0), | 275 video_rotation_(VIDEO_ROTATION_0), |
275 is_enabled_(true), | 276 is_enabled_(true), |
276 waiting_for_keyframe_(false), | 277 waiting_for_keyframe_(false), |
(...skipping 541 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
818 const scoped_refptr<MediaLog>& media_log) | 819 const scoped_refptr<MediaLog>& media_log) |
819 : host_(NULL), | 820 : host_(NULL), |
820 task_runner_(task_runner), | 821 task_runner_(task_runner), |
821 blocking_thread_("FFmpegDemuxer"), | 822 blocking_thread_("FFmpegDemuxer"), |
822 pending_read_(false), | 823 pending_read_(false), |
823 pending_seek_(false), | 824 pending_seek_(false), |
824 data_source_(data_source), | 825 data_source_(data_source), |
825 media_log_(media_log), | 826 media_log_(media_log), |
826 bitrate_(0), | 827 bitrate_(0), |
827 start_time_(kNoTimestamp), | 828 start_time_(kNoTimestamp), |
828 preferred_stream_for_seeking_(-1, kNoTimestamp), | |
829 fallback_stream_for_seeking_(-1, kNoTimestamp), | |
830 text_enabled_(false), | 829 text_enabled_(false), |
831 duration_known_(false), | 830 duration_known_(false), |
832 encrypted_media_init_data_cb_(encrypted_media_init_data_cb), | 831 encrypted_media_init_data_cb_(encrypted_media_init_data_cb), |
833 media_tracks_updated_cb_(media_tracks_updated_cb), | 832 media_tracks_updated_cb_(media_tracks_updated_cb), |
834 weak_factory_(this) { | 833 weak_factory_(this) { |
835 DCHECK(task_runner_.get()); | 834 DCHECK(task_runner_.get()); |
836 DCHECK(data_source_); | 835 DCHECK(data_source_); |
837 DCHECK(!media_tracks_updated_cb_.is_null()); | 836 DCHECK(!media_tracks_updated_cb_.is_null()); |
838 } | 837 } |
839 | 838 |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
944 | 943 |
945 // Choose the seeking stream based on whether it contains the seek time, if no | 944 // Choose the seeking stream based on whether it contains the seek time, if no |
946 // match can be found prefer the preferred stream. | 945 // match can be found prefer the preferred stream. |
947 // | 946 // |
948 // TODO(dalecurtis): Currently FFmpeg does not ensure that all streams in a | 947 // TODO(dalecurtis): Currently FFmpeg does not ensure that all streams in a |
949 // given container will demux all packets after the seek point. Instead it | 948 // given container will demux all packets after the seek point. Instead it |
950 // only guarantees that all packets after the file position of the seek will | 949 // only guarantees that all packets after the file position of the seek will |
951 // be demuxed. It's an open question whether FFmpeg should fix this: | 950 // be demuxed. It's an open question whether FFmpeg should fix this: |
952 // http://lists.ffmpeg.org/pipermail/ffmpeg-devel/2014-June/159212.html | 951 // http://lists.ffmpeg.org/pipermail/ffmpeg-devel/2014-June/159212.html |
953 // Tracked by http://crbug.com/387996. | 952 // Tracked by http://crbug.com/387996. |
954 DCHECK(preferred_stream_for_seeking_.second != kNoTimestamp); | 953 FFmpegDemuxerStream* demux_stream = FindPreferredStreamForSeeking(seek_time); |
955 const int stream_index = | 954 DCHECK(demux_stream); |
956 seek_time < preferred_stream_for_seeking_.second && | 955 const AVStream* seeking_stream = demux_stream->av_stream(); |
957 seek_time >= fallback_stream_for_seeking_.second | 956 DCHECK(seeking_stream); |
958 ? fallback_stream_for_seeking_.first | |
959 : preferred_stream_for_seeking_.first; | |
960 DCHECK_NE(stream_index, -1); | |
961 | |
962 const AVStream* seeking_stream = | |
963 glue_->format_context()->streams[stream_index]; | |
964 | 957 |
965 pending_seek_ = true; | 958 pending_seek_ = true; |
966 base::PostTaskAndReplyWithResult( | 959 base::PostTaskAndReplyWithResult( |
967 blocking_thread_.task_runner().get(), | 960 blocking_thread_.task_runner().get(), |
968 FROM_HERE, | 961 FROM_HERE, |
969 base::Bind(&av_seek_frame, | 962 base::Bind(&av_seek_frame, |
970 glue_->format_context(), | 963 glue_->format_context(), |
971 seeking_stream->index, | 964 seeking_stream->index, |
972 ConvertToTimeBase(seeking_stream->time_base, seek_time), | 965 ConvertToTimeBase(seeking_stream->time_base, seek_time), |
973 // Always seek to a timestamp <= to the desired timestamp. | 966 // Always seek to a timestamp <= to the desired timestamp. |
(...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1311 track_id_to_demux_stream_map_.end()); | 1304 track_id_to_demux_stream_map_.end()); |
1312 track_id_to_demux_stream_map_[media_track->id()] = streams_[i]; | 1305 track_id_to_demux_stream_map_[media_track->id()] = streams_[i]; |
1313 } | 1306 } |
1314 | 1307 |
1315 max_duration = std::max(max_duration, streams_[i]->duration()); | 1308 max_duration = std::max(max_duration, streams_[i]->duration()); |
1316 | 1309 |
1317 const base::TimeDelta start_time = | 1310 const base::TimeDelta start_time = |
1318 ExtractStartTime(stream, start_time_estimates[i]); | 1311 ExtractStartTime(stream, start_time_estimates[i]); |
1319 const bool has_start_time = start_time != kNoTimestamp; | 1312 const bool has_start_time = start_time != kNoTimestamp; |
1320 | 1313 |
1321 // Always prefer the video stream for seeking. If none exists, we'll swap | |
1322 // the fallback stream with the preferred stream below. | |
1323 if (codec_type == AVMEDIA_TYPE_VIDEO) { | |
1324 preferred_stream_for_seeking_ = | |
1325 StreamSeekInfo(i, has_start_time ? start_time : base::TimeDelta()); | |
1326 } | |
1327 | |
1328 if (!has_start_time) | 1314 if (!has_start_time) |
1329 continue; | 1315 continue; |
1330 | 1316 |
1317 streams_[i]->set_start_time(start_time); | |
1331 if (start_time < start_time_) { | 1318 if (start_time < start_time_) { |
1332 start_time_ = start_time; | 1319 start_time_ = start_time; |
1333 | |
1334 // Choose the stream with the lowest starting time as the fallback stream | |
1335 // for seeking. Video should always be preferred. | |
1336 fallback_stream_for_seeking_ = StreamSeekInfo(i, start_time); | |
1337 } | 1320 } |
1338 } | 1321 } |
1339 | 1322 |
1340 RecordDetectedTrackTypeStats(detected_audio_track_count, | 1323 RecordDetectedTrackTypeStats(detected_audio_track_count, |
1341 detected_video_track_count, | 1324 detected_video_track_count, |
1342 detected_text_track_count); | 1325 detected_text_track_count); |
1343 | 1326 |
1344 if (!audio_stream && !video_stream) { | 1327 if (!audio_stream && !video_stream) { |
1345 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() | 1328 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() |
1346 << ": no supported streams"; | 1329 << ": no supported streams"; |
(...skipping 29 matching lines...) Expand all Loading... | |
1376 // in section A.2 in the Ogg Vorbis spec: | 1359 // in section A.2 in the Ogg Vorbis spec: |
1377 // http://xiph.org/vorbis/doc/Vorbis_I_spec.html | 1360 // http://xiph.org/vorbis/doc/Vorbis_I_spec.html |
1378 // | 1361 // |
1379 // FFmpeg's use of negative timestamps for opus pre-skip is nonstandard, but | 1362 // FFmpeg's use of negative timestamps for opus pre-skip is nonstandard, but |
1380 // for more information on pre-skip see section 4.2 of the Ogg Opus spec: | 1363 // for more information on pre-skip see section 4.2 of the Ogg Opus spec: |
1381 // https://tools.ietf.org/html/draft-ietf-codec-oggopus-08#section-4.2 | 1364 // https://tools.ietf.org/html/draft-ietf-codec-oggopus-08#section-4.2 |
1382 if (audio_stream && (audio_stream->codec->codec_id == AV_CODEC_ID_OPUS || | 1365 if (audio_stream && (audio_stream->codec->codec_id == AV_CODEC_ID_OPUS || |
1383 (strcmp(format_context->iformat->name, "ogg") == 0 && | 1366 (strcmp(format_context->iformat->name, "ogg") == 0 && |
1384 audio_stream->codec->codec_id == AV_CODEC_ID_VORBIS))) { | 1367 audio_stream->codec->codec_id == AV_CODEC_ID_VORBIS))) { |
1385 for (size_t i = 0; i < streams_.size(); ++i) { | 1368 for (size_t i = 0; i < streams_.size(); ++i) { |
1386 if (streams_[i]) | 1369 if (!streams_[i]) |
1387 streams_[i]->enable_negative_timestamp_fixups(); | 1370 continue; |
1388 } | 1371 streams_[i]->enable_negative_timestamp_fixups(); |
1389 | 1372 |
1390 // Fixup the seeking information to avoid selecting the audio stream simply | 1373 // Fixup the seeking information to avoid selecting the audio stream |
1391 // because it has a lower starting time. | 1374 // simply because it has a lower starting time. |
1392 if (fallback_stream_for_seeking_.first == audio_stream->index && | 1375 if (streams_[i]->av_stream() == audio_stream && |
1393 fallback_stream_for_seeking_.second < base::TimeDelta()) { | 1376 streams_[i]->start_time() < base::TimeDelta()) { |
1394 fallback_stream_for_seeking_.second = base::TimeDelta(); | 1377 streams_[i]->set_start_time(base::TimeDelta()); |
1378 } | |
1395 } | 1379 } |
1396 } | 1380 } |
1397 | 1381 |
1398 // If no start time could be determined, default to zero and prefer the video | 1382 // If no start time could be determined, default to zero. |
1399 // stream over the audio stream for seeking. E.g., The WAV demuxer does not | |
1400 // put timestamps on its frames. | |
1401 if (start_time_ == kInfiniteDuration) { | 1383 if (start_time_ == kInfiniteDuration) { |
1402 start_time_ = base::TimeDelta(); | 1384 start_time_ = base::TimeDelta(); |
1403 preferred_stream_for_seeking_ = StreamSeekInfo( | |
1404 video_stream ? video_stream->index : audio_stream->index, start_time_); | |
1405 } else if (!video_stream) { | |
1406 // If no video stream exists, use the audio or text stream found above. | |
1407 preferred_stream_for_seeking_ = fallback_stream_for_seeking_; | |
1408 } | 1385 } |
1409 | 1386 |
1410 // MPEG-4 B-frames cause grief for a simple container like AVI. Enable PTS | 1387 // MPEG-4 B-frames cause grief for a simple container like AVI. Enable PTS |
1411 // generation so we always get timestamps, see http://crbug.com/169570 | 1388 // generation so we always get timestamps, see http://crbug.com/169570 |
1412 if (strcmp(format_context->iformat->name, "avi") == 0) | 1389 if (strcmp(format_context->iformat->name, "avi") == 0) |
1413 format_context->flags |= AVFMT_FLAG_GENPTS; | 1390 format_context->flags |= AVFMT_FLAG_GENPTS; |
1414 | 1391 |
1415 // For testing purposes, don't overwrite the timeline offset if set already. | 1392 // For testing purposes, don't overwrite the timeline offset if set already. |
1416 if (timeline_offset_.is_null()) | 1393 if (timeline_offset_.is_null()) |
1417 timeline_offset_ = ExtractTimelineOffset(format_context); | 1394 timeline_offset_ = ExtractTimelineOffset(format_context); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1483 SetTimeProperty(metadata_event.get(), "max_duration", max_duration); | 1460 SetTimeProperty(metadata_event.get(), "max_duration", max_duration); |
1484 SetTimeProperty(metadata_event.get(), "start_time", start_time_); | 1461 SetTimeProperty(metadata_event.get(), "start_time", start_time_); |
1485 metadata_event->params.SetInteger("bitrate", bitrate_); | 1462 metadata_event->params.SetInteger("bitrate", bitrate_); |
1486 media_log_->AddEvent(std::move(metadata_event)); | 1463 media_log_->AddEvent(std::move(metadata_event)); |
1487 | 1464 |
1488 media_tracks_updated_cb_.Run(std::move(media_tracks)); | 1465 media_tracks_updated_cb_.Run(std::move(media_tracks)); |
1489 | 1466 |
1490 status_cb.Run(PIPELINE_OK); | 1467 status_cb.Run(PIPELINE_OK); |
1491 } | 1468 } |
1492 | 1469 |
1470 FFmpegDemuxerStream* FFmpegDemuxer::FindPreferredStreamForSeeking( | |
1471 base::TimeDelta seek_time) { | |
1472 // If we have a selected/enabled video stream and its start time is lower | |
1473 // than the |seek_time| or unknown, then always prefer it for seeking. | |
1474 FFmpegDemuxerStream* video_stream = nullptr; | |
1475 for (const auto& stream : streams_) { | |
1476 if (stream && stream->type() == DemuxerStream::VIDEO && stream->enabled()) { | |
1477 video_stream = stream; | |
1478 break; | |
1479 } | |
1480 } | |
1481 if (video_stream && (video_stream->start_time() == kNoTimestamp || | |
DaleCurtis
2016/08/26 18:21:56
Merge into l.1477?
servolk
2016/08/26 19:08:44
Done.
| |
1482 video_stream->start_time() <= seek_time)) { | |
1483 return video_stream; | |
1484 } | |
1485 | |
1486 // If video stream is not present or |seek_time| is lower than the video start | |
1487 // time, then try to find an enabled stream with the lowest start time. | |
1488 FFmpegDemuxerStream* lowest_start_time_stream = nullptr; | |
1489 for (const auto& stream : streams_) { | |
1490 if (!stream || !stream->enabled() || stream->start_time() == kNoTimestamp) | |
1491 continue; | |
1492 if (!lowest_start_time_stream || | |
1493 stream->start_time() < lowest_start_time_stream->start_time()) { | |
1494 lowest_start_time_stream = stream; | |
1495 } | |
1496 } | |
1497 // If we found a stream with start time lower than |seek_time|, then use it. | |
1498 if (lowest_start_time_stream && | |
1499 lowest_start_time_stream->start_time() <= seek_time) { | |
1500 return lowest_start_time_stream; | |
1501 } | |
1502 | |
1503 // If we couldn't find any streams with the start time lower than |seek_time| | |
1504 // then use either video (if one exists) or any audio stream. | |
1505 if (video_stream) | |
DaleCurtis
2016/08/26 18:21:56
Ternary?
servolk
2016/08/26 19:08:44
Done.
| |
1506 return video_stream; | |
1507 return static_cast<FFmpegDemuxerStream*>(GetStream(DemuxerStream::AUDIO)); | |
1508 } | |
1509 | |
1493 void FFmpegDemuxer::OnSeekFrameDone(const PipelineStatusCB& cb, int result) { | 1510 void FFmpegDemuxer::OnSeekFrameDone(const PipelineStatusCB& cb, int result) { |
1494 DCHECK(task_runner_->BelongsToCurrentThread()); | 1511 DCHECK(task_runner_->BelongsToCurrentThread()); |
1495 CHECK(pending_seek_); | 1512 CHECK(pending_seek_); |
1496 pending_seek_ = false; | 1513 pending_seek_ = false; |
1497 | 1514 |
1498 if (!blocking_thread_.IsRunning()) { | 1515 if (!blocking_thread_.IsRunning()) { |
1499 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; | 1516 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; |
1500 cb.Run(PIPELINE_ERROR_ABORT); | 1517 cb.Run(PIPELINE_ERROR_ABORT); |
1501 return; | 1518 return; |
1502 } | 1519 } |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1697 | 1714 |
1698 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { | 1715 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { |
1699 DCHECK(task_runner_->BelongsToCurrentThread()); | 1716 DCHECK(task_runner_->BelongsToCurrentThread()); |
1700 for (auto* stream : streams_) { | 1717 for (auto* stream : streams_) { |
1701 if (stream) | 1718 if (stream) |
1702 stream->SetLiveness(liveness); | 1719 stream->SetLiveness(liveness); |
1703 } | 1720 } |
1704 } | 1721 } |
1705 | 1722 |
1706 } // namespace media | 1723 } // namespace media |
OLD | NEW |