// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "media/formats/mp2t/timestamp_unroller.h" #include "base/logging.h" namespace media { namespace mp2t { TimestampUnroller::TimestampUnroller() : is_previous_timestamp_valid_(false), previous_unrolled_timestamp_(0) { } TimestampUnroller::~TimestampUnroller() { } int64 TimestampUnroller::GetUnrolledTimestamp(int64 timestamp) { // Mpeg2 TS timestamps have an accuracy of 33 bits. const int nbits = 33; // |timestamp| has a precision of |nbits| // so make sure the highest bits are set to 0. DCHECK_EQ((timestamp >> nbits), 0); if (!is_previous_timestamp_valid_) { previous_unrolled_timestamp_ = timestamp; is_previous_timestamp_valid_ = true; return timestamp; } // |timestamp| is known modulo 2^33, so estimate the highest bits // to minimize the discontinuity with the previous unrolled timestamp. // Three possibilities are considered to estimate the missing high bits // of |timestamp|. If the bits of the previous unrolled timestamp are // {b63, b62, ..., b0} and bits of |timestamp| are {0, ..., 0, a32, ..., a0} // then the 3 possibilities are: // 1) t1 = {b63, ..., b33, a32, ..., a0} (apply the same offset multiple // of 2^33 as the one used for the previous timestamp) // 2) t0 = t1 - 2^33 // 3) t2 = t1 + 2^33 // // A few remarks: // - the purpose of the timestamp unroller is only to unroll timestamps // in such a way timestamp continuity is satisfied. It can generate negative // values during that process. // - possible overflows are not considered here since 64 bits on a 90kHz // timescale is way enough to represent several years of playback. int64 previous_unrolled_time_high = (previous_unrolled_timestamp_ >> nbits); int64 time0 = ((previous_unrolled_time_high - 1) << nbits) | timestamp; int64 time1 = ((previous_unrolled_time_high + 0) << nbits) | timestamp; int64 time2 = ((previous_unrolled_time_high + 1) << nbits) | timestamp; // Select the min absolute difference with the current time // so as to ensure time continuity. int64 diff0 = time0 - previous_unrolled_timestamp_; int64 diff1 = time1 - previous_unrolled_timestamp_; int64 diff2 = time2 - previous_unrolled_timestamp_; if (diff0 < 0) diff0 = -diff0; if (diff1 < 0) diff1 = -diff1; if (diff2 < 0) diff2 = -diff2; int64 unrolled_time; int64 min_diff; if (diff1 < diff0) { unrolled_time = time1; min_diff = diff1; } else { unrolled_time = time0; min_diff = diff0; } if (diff2 < min_diff) unrolled_time = time2; // Update the state of the timestamp unroller. previous_unrolled_timestamp_ = unrolled_time; return unrolled_time; } void TimestampUnroller::Reset() { is_previous_timestamp_valid_ = false; previous_unrolled_timestamp_ = 0; } } // namespace mp2t } // namespace media