blob: b88c6a61b796f02776633538203572ba3d1ad3a1 [file] [log] [blame]
// 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 cobalt {
namespace media {
namespace mp2t {
TimestampUnroller::TimestampUnroller()
: is_previous_timestamp_valid_(false), previous_unrolled_timestamp_(0) {}
TimestampUnroller::~TimestampUnroller() {}
int64_t TimestampUnroller::GetUnrolledTimestamp(int64_t 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_t previous_unrolled_time_high = (previous_unrolled_timestamp_ >> nbits);
int64_t time0 = ((previous_unrolled_time_high - 1) << nbits) | timestamp;
int64_t time1 = ((previous_unrolled_time_high + 0) << nbits) | timestamp;
int64_t time2 = ((previous_unrolled_time_high + 1) << nbits) | timestamp;
// Select the min absolute difference with the current time
// so as to ensure time continuity.
int64_t diff0 = time0 - previous_unrolled_timestamp_;
int64_t diff1 = time1 - previous_unrolled_timestamp_;
int64_t diff2 = time2 - previous_unrolled_timestamp_;
if (diff0 < 0) diff0 = -diff0;
if (diff1 < 0) diff1 = -diff1;
if (diff2 < 0) diff2 = -diff2;
int64_t unrolled_time;
int64_t 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
} // namespace cobalt