Commit 1e66d75f authored by Dan Sanders's avatar Dan Sanders Committed by Commit Bot

[media] Check for overflow in TrackRunIterator::cts().

This CL moves the CTS computation to AdvanceSample(), which now returns
a bool. Callers have been updated to fail when AdvanceSample() fails.

Bug: 772874
Change-Id: I1215f6a259eff310b964e1899be4e4138ff34087
Reviewed-on: https://chromium-review.googlesource.com/722164Reviewed-by: default avatarMatthew Wolenetz <wolenetz@chromium.org>
Commit-Queue: Matthew Wolenetz <wolenetz@chromium.org>
Commit-Queue: Dan Sanders <sandersd@chromium.org>
Cr-Commit-Position: refs/heads/master@{#509664}
parent 84eb950e
...@@ -618,7 +618,9 @@ bool MP4StreamParser::EnqueueSample(BufferQueueMap* buffers, bool* err) { ...@@ -618,7 +618,9 @@ bool MP4StreamParser::EnqueueSample(BufferQueueMap* buffers, bool* err) {
} }
if (!runs_->IsSampleValid()) { if (!runs_->IsSampleValid()) {
runs_->AdvanceRun(); *err = !runs_->AdvanceRun();
if (*err)
return false;
return true; return true;
} }
...@@ -636,7 +638,9 @@ bool MP4StreamParser::EnqueueSample(BufferQueueMap* buffers, bool* err) { ...@@ -636,7 +638,9 @@ bool MP4StreamParser::EnqueueSample(BufferQueueMap* buffers, bool* err) {
// Skip this entire track if it's not one we're interested in // Skip this entire track if it's not one we're interested in
if (!audio && !video) { if (!audio && !video) {
runs_->AdvanceRun(); *err = !runs_->AdvanceRun();
if (*err)
return false;
return true; return true;
} }
...@@ -674,7 +678,9 @@ bool MP4StreamParser::EnqueueSample(BufferQueueMap* buffers, bool* err) { ...@@ -674,7 +678,9 @@ bool MP4StreamParser::EnqueueSample(BufferQueueMap* buffers, bool* err) {
LIMITED_MEDIA_LOG(DEBUG, media_log_, num_empty_samples_skipped_, LIMITED_MEDIA_LOG(DEBUG, media_log_, num_empty_samples_skipped_,
kMaxEmptySampleLogs) kMaxEmptySampleLogs)
<< "Skipping 'trun' sample with size of 0."; << "Skipping 'trun' sample with size of 0.";
runs_->AdvanceSample(); *err = !runs_->AdvanceSample();
if (*err)
return false;
return true; return true;
} }
...@@ -757,7 +763,7 @@ bool MP4StreamParser::EnqueueSample(BufferQueueMap* buffers, bool* err) { ...@@ -757,7 +763,7 @@ bool MP4StreamParser::EnqueueSample(BufferQueueMap* buffers, bool* err) {
if (runs_->cts() != kNoTimestamp) { if (runs_->cts() != kNoTimestamp) {
stream_buf->set_timestamp(runs_->cts()); stream_buf->set_timestamp(runs_->cts());
} else { } else {
MEDIA_LOG(ERROR, media_log_) << "Frame CTS exceeds representable limit"; MEDIA_LOG(ERROR, media_log_) << "Frame PTS exceeds representable limit";
*err = true; *err = true;
return false; return false;
} }
...@@ -779,7 +785,9 @@ bool MP4StreamParser::EnqueueSample(BufferQueueMap* buffers, bool* err) { ...@@ -779,7 +785,9 @@ bool MP4StreamParser::EnqueueSample(BufferQueueMap* buffers, bool* err) {
<< ", size=" << sample_size; << ", size=" << sample_size;
(*buffers)[runs_->track_id()].push_back(stream_buf); (*buffers)[runs_->track_id()].push_back(stream_buf);
runs_->AdvanceSample(); *err = !runs_->AdvanceSample();
if (*err)
return false;
return true; return true;
} }
...@@ -848,10 +856,11 @@ bool MP4StreamParser::ComputeHighestEndOffset(const MovieFragment& moof) { ...@@ -848,10 +856,11 @@ bool MP4StreamParser::ComputeHighestEndOffset(const MovieFragment& moof) {
int64_t sample_end_offset = runs.sample_offset() + runs.sample_size(); int64_t sample_end_offset = runs.sample_offset() + runs.sample_size();
if (sample_end_offset > highest_end_offset_) if (sample_end_offset > highest_end_offset_)
highest_end_offset_ = sample_end_offset; highest_end_offset_ = sample_end_offset;
if (!runs.AdvanceSample())
runs.AdvanceSample(); return false;
} }
runs.AdvanceRun(); if (!runs.AdvanceRun())
return false;
} }
return true; return true;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <memory> #include <memory>
#include "base/macros.h" #include "base/macros.h"
#include "base/numerics/checked_math.h"
#include "media/base/timestamp_constants.h" #include "media/base/timestamp_constants.h"
#include "media/formats/mp4/rcheck.h" #include "media/formats/mp4/rcheck.h"
#include "media/formats/mp4/sample_to_group_iterator.h" #include "media/formats/mp4/sample_to_group_iterator.h"
...@@ -149,12 +150,13 @@ static bool PopulateSampleInfo(const TrackExtends& trex, ...@@ -149,12 +150,13 @@ static bool PopulateSampleInfo(const TrackExtends& trex,
sample_info->duration = trex.default_sample_duration; sample_info->duration = trex.default_sample_duration;
} }
if (i < trun.sample_composition_time_offsets.size()) { auto cts_offset = -base::CheckedNumeric<int64_t>(edit_list_offset);
sample_info->cts_offset = trun.sample_composition_time_offsets[i]; if (i < trun.sample_composition_time_offsets.size())
} else { cts_offset += trun.sample_composition_time_offsets[i];
sample_info->cts_offset = 0; if (!cts_offset.AssignIfValid(&sample_info->cts_offset)) {
MEDIA_LOG(ERROR, media_log) << "PTS offset exceeds representable range.";
return false;
} }
sample_info->cts_offset += edit_list_offset;
uint32_t flags; uint32_t flags;
if (i < trun.sample_flags.size()) { if (i < trun.sample_flags.size()) {
...@@ -316,7 +318,7 @@ bool TrackRunIterator::Init(const MovieFragment& moof) { ...@@ -316,7 +318,7 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
if (edits[0].media_time < 0) { if (edits[0].media_time < 0) {
DVLOG(1) << "Empty edit list entry ignored."; DVLOG(1) << "Empty edit list entry ignored.";
} else { } else {
edit_list_offset = -edits[0].media_time; edit_list_offset = edits[0].media_time;
} }
} }
...@@ -486,27 +488,48 @@ bool TrackRunIterator::Init(const MovieFragment& moof) { ...@@ -486,27 +488,48 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
std::sort(runs_.begin(), runs_.end(), CompareMinTrackRunDataOffset()); std::sort(runs_.begin(), runs_.end(), CompareMinTrackRunDataOffset());
run_itr_ = runs_.begin(); run_itr_ = runs_.begin();
ResetRun(); return ResetRun();
}
bool TrackRunIterator::UpdateCts() {
// TODO(sandersd): Should |sample_cts_| be cleared in this case?
if (!IsSampleValid())
return true;
auto cts = base::CheckAdd(sample_dts_, sample_itr_->cts_offset);
if (!cts.AssignIfValid(&sample_cts_)) {
MEDIA_LOG(ERROR, media_log_) << "Sample PTS exceeds representable range.";
return false;
}
return true; return true;
} }
void TrackRunIterator::AdvanceRun() { bool TrackRunIterator::AdvanceRun() {
++run_itr_; ++run_itr_;
ResetRun(); return ResetRun();
} }
void TrackRunIterator::ResetRun() { bool TrackRunIterator::ResetRun() {
if (!IsRunValid()) return; // TODO(sandersd): Should we clear all the values if the run is not valid?
if (!IsRunValid())
return true;
sample_dts_ = run_itr_->start_dts; sample_dts_ = run_itr_->start_dts;
sample_offset_ = run_itr_->sample_start_offset; sample_offset_ = run_itr_->sample_start_offset;
sample_itr_ = run_itr_->samples.begin(); sample_itr_ = run_itr_->samples.begin();
// UpdateCts() must run after |sample_itr_| is updated to the current run.
return UpdateCts();
} }
void TrackRunIterator::AdvanceSample() { bool TrackRunIterator::AdvanceSample() {
DCHECK(IsSampleValid()); DCHECK(IsSampleValid());
sample_dts_ += sample_itr_->duration; auto dts = base::CheckAdd(sample_dts_, sample_itr_->duration);
if (!dts.AssignIfValid(&sample_dts_)) {
MEDIA_LOG(ERROR, media_log_) << "Sample DTS exceeds representable range.";
return false;
}
sample_offset_ += sample_itr_->size; sample_offset_ += sample_itr_->size;
++sample_itr_; ++sample_itr_;
// UpdateCts() must run after |sample_itr_| is updated to the current sample.
return UpdateCts();
} }
// This implementation only indicates a need for caching if CENC auxiliary // This implementation only indicates a need for caching if CENC auxiliary
...@@ -638,8 +661,7 @@ DecodeTimestamp TrackRunIterator::dts() const { ...@@ -638,8 +661,7 @@ DecodeTimestamp TrackRunIterator::dts() const {
base::TimeDelta TrackRunIterator::cts() const { base::TimeDelta TrackRunIterator::cts() const {
DCHECK(IsSampleValid()); DCHECK(IsSampleValid());
return TimeDeltaFromRational(sample_dts_ + sample_itr_->cts_offset, return TimeDeltaFromRational(sample_cts_, run_itr_->timescale);
run_itr_->timescale);
} }
base::TimeDelta TrackRunIterator::duration() const { base::TimeDelta TrackRunIterator::duration() const {
......
...@@ -47,10 +47,12 @@ class MEDIA_EXPORT TrackRunIterator { ...@@ -47,10 +47,12 @@ class MEDIA_EXPORT TrackRunIterator {
bool IsRunValid() const; bool IsRunValid() const;
bool IsSampleValid() const; bool IsSampleValid() const;
// Advance the properties to refer to the next run or sample. Requires that // Advance the properties to refer to the next run or sample. These return
// the current sample be valid. // |false| on failure, but note that advancing to the end (IsRunValid() or
void AdvanceRun(); // IsSampleValid() return false) is not a failure, and the properties are not
void AdvanceSample(); // guaranteed to be consistent in that case.
bool AdvanceRun();
bool AdvanceSample();
// Returns true if this track run has auxiliary information and has not yet // Returns true if this track run has auxiliary information and has not yet
// been cached. Only valid if IsRunValid(). // been cached. Only valid if IsRunValid().
...@@ -91,7 +93,8 @@ class MEDIA_EXPORT TrackRunIterator { ...@@ -91,7 +93,8 @@ class MEDIA_EXPORT TrackRunIterator {
std::unique_ptr<DecryptConfig> GetDecryptConfig(); std::unique_ptr<DecryptConfig> GetDecryptConfig();
private: private:
void ResetRun(); bool UpdateCts();
bool ResetRun();
const TrackEncryption& track_encryption() const; const TrackEncryption& track_encryption() const;
uint32_t GetGroupDescriptionIndex(uint32_t sample_index) const; uint32_t GetGroupDescriptionIndex(uint32_t sample_index) const;
...@@ -112,6 +115,7 @@ class MEDIA_EXPORT TrackRunIterator { ...@@ -112,6 +115,7 @@ class MEDIA_EXPORT TrackRunIterator {
std::vector<SampleInfo>::const_iterator sample_itr_; std::vector<SampleInfo>::const_iterator sample_itr_;
int64_t sample_dts_; int64_t sample_dts_;
int64_t sample_cts_;
int64_t sample_offset_; int64_t sample_offset_;
DISALLOW_COPY_AND_ASSIGN(TrackRunIterator); DISALLOW_COPY_AND_ASSIGN(TrackRunIterator);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment