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> |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 | 67 |
68 static base::TimeDelta FramesToTimeDelta(int frames, double sample_rate) { | 68 static base::TimeDelta FramesToTimeDelta(int frames, double sample_rate) { |
69 return base::TimeDelta::FromMicroseconds( | 69 return base::TimeDelta::FromMicroseconds( |
70 frames * base::Time::kMicrosecondsPerSecond / sample_rate); | 70 frames * base::Time::kMicrosecondsPerSecond / sample_rate); |
71 } | 71 } |
72 | 72 |
73 static base::TimeDelta ExtractStartTime(AVStream* stream, | 73 static base::TimeDelta ExtractStartTime(AVStream* stream, |
74 base::TimeDelta start_time_estimate) { | 74 base::TimeDelta start_time_estimate) { |
75 DCHECK(start_time_estimate != kNoTimestamp); | 75 DCHECK(start_time_estimate != kNoTimestamp); |
76 if (stream->start_time == static_cast<int64_t>(AV_NOPTS_VALUE)) { | 76 if (stream->start_time == static_cast<int64_t>(AV_NOPTS_VALUE)) { |
77 return start_time_estimate == kInfiniteDuration ? kNoTimestamp | 77 return start_time_estimate == kInfiniteDuration ? base::TimeDelta() |
78 : start_time_estimate; | 78 : start_time_estimate; |
79 } | 79 } |
80 | 80 |
81 // First try the lower of the estimate and the |start_time| value. | 81 // First try the lower of the estimate and the |start_time| value. |
82 base::TimeDelta start_time = | 82 base::TimeDelta start_time = |
83 std::min(ConvertFromTimeBase(stream->time_base, stream->start_time), | 83 std::min(ConvertFromTimeBase(stream->time_base, stream->start_time), |
84 start_time_estimate); | 84 start_time_estimate); |
85 | 85 |
86 // Next see if the first buffered pts value is usable. | 86 // Next see if the first buffered pts value is usable. |
87 if (stream->pts_buffer[0] != static_cast<int64_t>(AV_NOPTS_VALUE)) { | 87 if (stream->pts_buffer[0] != static_cast<int64_t>(AV_NOPTS_VALUE)) { |
(...skipping 1244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1332 media_track->set_id(base::UintToString(track_id)); | 1332 media_track->set_id(base::UintToString(track_id)); |
1333 DCHECK(track_id_to_demux_stream_map_.find(media_track->id()) == | 1333 DCHECK(track_id_to_demux_stream_map_.find(media_track->id()) == |
1334 track_id_to_demux_stream_map_.end()); | 1334 track_id_to_demux_stream_map_.end()); |
1335 track_id_to_demux_stream_map_[media_track->id()] = streams_[i].get(); | 1335 track_id_to_demux_stream_map_[media_track->id()] = streams_[i].get(); |
1336 } | 1336 } |
1337 | 1337 |
1338 max_duration = std::max(max_duration, streams_[i]->duration()); | 1338 max_duration = std::max(max_duration, streams_[i]->duration()); |
1339 | 1339 |
1340 const base::TimeDelta start_time = | 1340 const base::TimeDelta start_time = |
1341 ExtractStartTime(stream, start_time_estimates[i]); | 1341 ExtractStartTime(stream, start_time_estimates[i]); |
1342 const bool has_start_time = start_time != kNoTimestamp; | |
1343 | |
1344 if (!has_start_time) | |
1345 continue; | |
1346 | |
1347 streams_[i]->set_start_time(start_time); | 1342 streams_[i]->set_start_time(start_time); |
1348 if (start_time < start_time_) { | 1343 if (start_time < start_time_) { |
1349 start_time_ = start_time; | 1344 start_time_ = start_time; |
1350 } | 1345 } |
1351 } | 1346 } |
1352 | 1347 |
1353 RecordDetectedTrackTypeStats(detected_audio_track_count, | 1348 RecordDetectedTrackTypeStats(detected_audio_track_count, |
1354 detected_video_track_count, | 1349 detected_video_track_count, |
1355 detected_text_track_count); | 1350 detected_text_track_count); |
1356 | 1351 |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1516 } | 1511 } |
1517 } | 1512 } |
1518 params.SetBoolean("found_audio_stream", (audio_track_count > 0)); | 1513 params.SetBoolean("found_audio_stream", (audio_track_count > 0)); |
1519 params.SetBoolean("found_video_stream", (video_track_count > 0)); | 1514 params.SetBoolean("found_video_stream", (video_track_count > 0)); |
1520 SetTimeProperty(metadata_event.get(), "max_duration", max_duration); | 1515 SetTimeProperty(metadata_event.get(), "max_duration", max_duration); |
1521 SetTimeProperty(metadata_event.get(), "start_time", start_time_); | 1516 SetTimeProperty(metadata_event.get(), "start_time", start_time_); |
1522 metadata_event->params.SetInteger("bitrate", bitrate_); | 1517 metadata_event->params.SetInteger("bitrate", bitrate_); |
1523 media_log_->AddEvent(std::move(metadata_event)); | 1518 media_log_->AddEvent(std::move(metadata_event)); |
1524 } | 1519 } |
1525 | 1520 |
| 1521 FFmpegDemuxerStream* FFmpegDemuxer::FindStreamWithLowestStartTimestamp( |
| 1522 bool enabled) { |
| 1523 FFmpegDemuxerStream* lowest_start_time_stream = nullptr; |
| 1524 for (const auto& stream : streams_) { |
| 1525 if (!stream || stream->enabled() != enabled) |
| 1526 continue; |
| 1527 if (!lowest_start_time_stream || |
| 1528 stream->start_time() < lowest_start_time_stream->start_time()) { |
| 1529 lowest_start_time_stream = stream.get(); |
| 1530 } |
| 1531 } |
| 1532 return lowest_start_time_stream; |
| 1533 } |
| 1534 |
1526 FFmpegDemuxerStream* FFmpegDemuxer::FindPreferredStreamForSeeking( | 1535 FFmpegDemuxerStream* FFmpegDemuxer::FindPreferredStreamForSeeking( |
1527 base::TimeDelta seek_time) { | 1536 base::TimeDelta seek_time) { |
1528 // If we have a selected/enabled video stream and its start time is lower | 1537 // If we have a selected/enabled video stream and its start time is lower |
1529 // than the |seek_time| or unknown, then always prefer it for seeking. | 1538 // than the |seek_time| or unknown, then always prefer it for seeking. |
1530 FFmpegDemuxerStream* video_stream = nullptr; | 1539 FFmpegDemuxerStream* video_stream = nullptr; |
1531 for (const auto& stream : streams_) { | 1540 for (const auto& stream : streams_) { |
1532 if (stream && stream->type() == DemuxerStream::VIDEO && stream->enabled()) { | 1541 if (stream && stream->type() == DemuxerStream::VIDEO && stream->enabled()) { |
1533 video_stream = stream.get(); | 1542 video_stream = stream.get(); |
1534 if (video_stream->start_time() == kNoTimestamp || | 1543 if (video_stream->start_time() <= seek_time) { |
1535 video_stream->start_time() <= seek_time) { | |
1536 return video_stream; | 1544 return video_stream; |
1537 } | 1545 } |
1538 break; | 1546 break; |
1539 } | 1547 } |
1540 } | 1548 } |
1541 | 1549 |
1542 // If video stream is not present or |seek_time| is lower than the video start | 1550 // If video stream is not present or |seek_time| is lower than the video start |
1543 // time, then try to find an enabled stream with the lowest start time. | 1551 // time, then try to find an enabled stream with the lowest start time. |
1544 FFmpegDemuxerStream* lowest_start_time_stream = nullptr; | 1552 FFmpegDemuxerStream* lowest_start_time_enabled_stream = |
1545 for (const auto& stream : streams_) { | 1553 FindStreamWithLowestStartTimestamp(true); |
1546 if (!stream || !stream->enabled() || stream->start_time() == kNoTimestamp) | 1554 if (lowest_start_time_enabled_stream && |
1547 continue; | 1555 lowest_start_time_enabled_stream->start_time() <= seek_time) { |
1548 if (!lowest_start_time_stream || | 1556 return lowest_start_time_enabled_stream; |
1549 stream->start_time() < lowest_start_time_stream->start_time()) { | |
1550 lowest_start_time_stream = stream.get(); | |
1551 } | |
1552 } | |
1553 // If we found a stream with start time lower than |seek_time|, then use it. | |
1554 if (lowest_start_time_stream && | |
1555 lowest_start_time_stream->start_time() <= seek_time) { | |
1556 return lowest_start_time_stream; | |
1557 } | 1557 } |
1558 | 1558 |
1559 // If we couldn't find any streams with the start time lower than |seek_time| | 1559 // If there's no enabled streams to consider from, try a disabled stream with |
1560 // then use either video (if one exists) or any audio stream. | 1560 // the lowest known start time. |
1561 return video_stream ? video_stream : static_cast<FFmpegDemuxerStream*>( | 1561 FFmpegDemuxerStream* lowest_start_time_disabled_stream = |
1562 GetStream(DemuxerStream::AUDIO)); | 1562 FindStreamWithLowestStartTimestamp(false); |
| 1563 if (lowest_start_time_disabled_stream && |
| 1564 lowest_start_time_disabled_stream->start_time() <= seek_time) { |
| 1565 return lowest_start_time_disabled_stream; |
| 1566 } |
| 1567 |
| 1568 // Otherwise fall back to any other stream. |
| 1569 for (const auto& stream : streams_) { |
| 1570 if (stream) |
| 1571 return stream.get(); |
| 1572 } |
| 1573 |
| 1574 NOTREACHED(); |
| 1575 return nullptr; |
1563 } | 1576 } |
1564 | 1577 |
1565 void FFmpegDemuxer::OnSeekFrameDone(int result) { | 1578 void FFmpegDemuxer::OnSeekFrameDone(int result) { |
1566 DCHECK(task_runner_->BelongsToCurrentThread()); | 1579 DCHECK(task_runner_->BelongsToCurrentThread()); |
1567 CHECK(!pending_seek_cb_.is_null()); | 1580 CHECK(!pending_seek_cb_.is_null()); |
1568 | 1581 |
1569 if (!blocking_thread_.IsRunning()) { | 1582 if (!blocking_thread_.IsRunning()) { |
1570 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; | 1583 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; |
1571 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_ERROR_ABORT); | 1584 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_ERROR_ABORT); |
1572 return; | 1585 return; |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1783 | 1796 |
1784 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { | 1797 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { |
1785 DCHECK(task_runner_->BelongsToCurrentThread()); | 1798 DCHECK(task_runner_->BelongsToCurrentThread()); |
1786 for (const auto& stream : streams_) { | 1799 for (const auto& stream : streams_) { |
1787 if (stream) | 1800 if (stream) |
1788 stream->SetLiveness(liveness); | 1801 stream->SetLiveness(liveness); |
1789 } | 1802 } |
1790 } | 1803 } |
1791 | 1804 |
1792 } // namespace media | 1805 } // namespace media |
OLD | NEW |