-
-
Notifications
You must be signed in to change notification settings - Fork 10.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The slope encodes the drift between the device clock and the computer clock. Its real value is expected very close to 1. To estimate it, just assume it is exactly 1. Since the clock is used to estimate very close points in the future, the error caused by clock drift is totally negligible, and in practice it is way lower than the slope estimation error. Therefore, only estimate the offset.
- Loading branch information
Showing
5 changed files
with
23 additions
and
213 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,116 +1,36 @@ | ||
#include "clock.h" | ||
|
||
#include <assert.h> | ||
|
||
#include "util/log.h" | ||
|
||
#define SC_CLOCK_NDEBUG // comment to debug | ||
|
||
#define SC_CLOCK_RANGE 32 | ||
|
||
void | ||
sc_clock_init(struct sc_clock *clock) { | ||
clock->count = 0; | ||
clock->head = 0; | ||
clock->left_sum.system = 0; | ||
clock->left_sum.stream = 0; | ||
clock->right_sum.system = 0; | ||
clock->right_sum.stream = 0; | ||
} | ||
|
||
// Estimate the affine function f(stream) = slope * stream + offset | ||
static void | ||
sc_clock_estimate(struct sc_clock *clock, | ||
double *out_slope, sc_tick *out_offset) { | ||
assert(clock->count); | ||
|
||
if (clock->count == 1) { | ||
// If there is only 1 point, we can't compute a slope. Assume it is 1. | ||
struct sc_clock_point *single_point = &clock->right_sum; | ||
*out_slope = 1; | ||
*out_offset = single_point->system - single_point->stream; | ||
return; | ||
} | ||
|
||
struct sc_clock_point left_avg = { | ||
.system = clock->left_sum.system / (clock->count / 2), | ||
.stream = clock->left_sum.stream / (clock->count / 2), | ||
}; | ||
struct sc_clock_point right_avg = { | ||
.system = clock->right_sum.system / ((clock->count + 1) / 2), | ||
.stream = clock->right_sum.stream / ((clock->count + 1) / 2), | ||
}; | ||
|
||
double slope = (double) (right_avg.system - left_avg.system) | ||
/ (right_avg.stream - left_avg.stream); | ||
|
||
if (clock->count < SC_CLOCK_RANGE) { | ||
/* The first frames are typically received and decoded with more delay | ||
* than the others, causing a wrong slope estimation on start. To | ||
* compensate, assume an initial slope of 1, then progressively use the | ||
* estimated slope. */ | ||
slope = (clock->count * slope + (SC_CLOCK_RANGE - clock->count)) | ||
/ SC_CLOCK_RANGE; | ||
} | ||
|
||
struct sc_clock_point global_avg = { | ||
.system = (clock->left_sum.system + clock->right_sum.system) | ||
/ clock->count, | ||
.stream = (clock->left_sum.stream + clock->right_sum.stream) | ||
/ clock->count, | ||
}; | ||
|
||
sc_tick offset = global_avg.system - (sc_tick) (global_avg.stream * slope); | ||
|
||
*out_slope = slope; | ||
*out_offset = offset; | ||
clock->range = 0; | ||
clock->offset = 0; | ||
} | ||
|
||
void | ||
sc_clock_update(struct sc_clock *clock, sc_tick system, sc_tick stream) { | ||
struct sc_clock_point *point = &clock->points[clock->head]; | ||
|
||
if (clock->count == SC_CLOCK_RANGE || clock->count & 1) { | ||
// One point passes from the right sum to the left sum | ||
|
||
unsigned mid; | ||
if (clock->count == SC_CLOCK_RANGE) { | ||
mid = (clock->head + SC_CLOCK_RANGE / 2) % SC_CLOCK_RANGE; | ||
} else { | ||
// Only for the first frames | ||
mid = clock->count / 2; | ||
} | ||
|
||
struct sc_clock_point *mid_point = &clock->points[mid]; | ||
clock->left_sum.system += mid_point->system; | ||
clock->left_sum.stream += mid_point->stream; | ||
clock->right_sum.system -= mid_point->system; | ||
clock->right_sum.stream -= mid_point->stream; | ||
if (clock->range < SC_CLOCK_RANGE) { | ||
++clock->range; | ||
} | ||
|
||
if (clock->count == SC_CLOCK_RANGE) { | ||
// The current point overwrites the previous value in the circular | ||
// array, update the left sum accordingly | ||
clock->left_sum.system -= point->system; | ||
clock->left_sum.stream -= point->stream; | ||
} else { | ||
++clock->count; | ||
} | ||
|
||
point->system = system; | ||
point->stream = stream; | ||
|
||
clock->right_sum.system += system; | ||
clock->right_sum.stream += stream; | ||
|
||
clock->head = (clock->head + 1) % SC_CLOCK_RANGE; | ||
|
||
// Update estimation | ||
sc_clock_estimate(clock, &clock->slope, &clock->offset); | ||
sc_tick offset = system - stream; | ||
clock->offset = ((clock->range - 1) * clock->offset + offset) | ||
/ clock->range; | ||
|
||
#ifndef SC_CLOCK_NDEBUG | ||
LOGD("Clock estimation: %f * pts + %" PRItick, clock->slope, clock->offset); | ||
LOGD("Clock estimation: pts + %" PRItick, clock->offset); | ||
#endif | ||
} | ||
|
||
sc_tick | ||
sc_clock_to_system_time(struct sc_clock *clock, sc_tick stream) { | ||
assert(clock->count); // sc_clock_update() must have been called | ||
return (sc_tick) (stream * clock->slope) + clock->offset; | ||
assert(clock->range); // sc_clock_update() must have been called | ||
return stream + clock->offset; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.