@@ -56,6 +56,14 @@ namespace mediapipe {
56
56
// If pad_final_packet is true, all input samples will be emitted and the final
57
57
// packet will be zero padded as necessary. If pad_final_packet is false, some
58
58
// samples may be dropped at the end of the stream.
59
+ //
60
+ // If use_local_timestamp is true, the output packet's timestamp is based on the
61
+ // last sample of the packet. The timestamp of this sample is inferred by
62
+ // input_packet_timesamp + local_sample_index / sampling_rate_. If false, the
63
+ // output packet's timestamp is based on the cumulative timestamping, which is
64
+ // done by adopting the timestamp of the first sample of the packet and this
65
+ // sample's timestamp is inferred by initial_input_timestamp_ +
66
+ // cumulative_completed_samples / sample_rate_.
59
67
class TimeSeriesFramerCalculator : public CalculatorBase {
60
68
public:
61
69
static ::mediapipe::Status GetContract (CalculatorContract* cc) {
@@ -86,11 +94,26 @@ class TimeSeriesFramerCalculator : public CalculatorBase {
86
94
void FrameOutput (CalculatorContext* cc);
87
95
88
96
Timestamp CurrentOutputTimestamp () {
97
+ if (use_local_timestamp_) {
98
+ return current_timestamp_;
99
+ }
100
+ return CumulativeOutputTimestamp ();
101
+ }
102
+
103
+ Timestamp CumulativeOutputTimestamp () {
89
104
return initial_input_timestamp_ +
90
105
round (cumulative_completed_samples_ / sample_rate_ *
91
106
Timestamp::kTimestampUnitsPerSecond );
92
107
}
93
108
109
+ // Returns the timestamp of a sample on a base, which is usually the time
110
+ // stamp of a packet.
111
+ Timestamp CurrentSampleTimestamp (const Timestamp& timestamp_base,
112
+ int64 number_of_samples) {
113
+ return timestamp_base + round (number_of_samples / sample_rate_ *
114
+ Timestamp::kTimestampUnitsPerSecond );
115
+ }
116
+
94
117
// The number of input samples to advance after the current output frame is
95
118
// emitted.
96
119
int next_frame_step_samples () const {
@@ -118,22 +141,27 @@ class TimeSeriesFramerCalculator : public CalculatorBase {
118
141
// any overlap).
119
142
int64 cumulative_completed_samples_;
120
143
Timestamp initial_input_timestamp_;
144
+ // The current timestamp is updated along with the incoming packets.
145
+ Timestamp current_timestamp_;
121
146
int num_channels_;
122
147
123
148
// Each entry in this deque consists of a single sample, i.e. a
124
- // single column vector.
125
- std::deque<Matrix> sample_buffer_;
149
+ // single column vector, and its timestamp .
150
+ std::deque<std::pair< Matrix, Timestamp> > sample_buffer_;
126
151
127
152
bool use_window_;
128
153
Matrix window_;
154
+
155
+ bool use_local_timestamp_;
129
156
};
130
157
REGISTER_CALCULATOR (TimeSeriesFramerCalculator);
131
158
132
159
void TimeSeriesFramerCalculator::EnqueueInput (CalculatorContext* cc) {
133
160
const Matrix& input_frame = cc->Inputs ().Index (0 ).Get <Matrix>();
134
161
135
162
for (int i = 0 ; i < input_frame.cols (); ++i) {
136
- sample_buffer_.emplace_back (input_frame.col (i));
163
+ sample_buffer_.emplace_back (std::make_pair (
164
+ input_frame.col (i), CurrentSampleTimestamp (cc->InputTimestamp (), i)));
137
165
}
138
166
139
167
cumulative_input_samples_ += input_frame.cols ();
@@ -151,14 +179,16 @@ void TimeSeriesFramerCalculator::FrameOutput(CalculatorContext* cc) {
151
179
new Matrix (num_channels_, frame_duration_samples_));
152
180
for (int i = 0 ; i < std::min (frame_step_samples, frame_duration_samples_);
153
181
++i) {
154
- output_frame->col (i) = sample_buffer_.front ();
182
+ output_frame->col (i) = sample_buffer_.front ().first ;
183
+ current_timestamp_ = sample_buffer_.front ().second ;
155
184
sample_buffer_.pop_front ();
156
185
}
157
186
const int frame_overlap_samples =
158
187
frame_duration_samples_ - frame_step_samples;
159
188
if (frame_overlap_samples > 0 ) {
160
189
for (int i = 0 ; i < frame_overlap_samples; ++i) {
161
- output_frame->col (i + frame_step_samples) = sample_buffer_[i];
190
+ output_frame->col (i + frame_step_samples) = sample_buffer_[i].first ;
191
+ current_timestamp_ = sample_buffer_[i].second ;
162
192
}
163
193
} else {
164
194
samples_still_to_drop_ = -frame_overlap_samples;
@@ -178,6 +208,7 @@ void TimeSeriesFramerCalculator::FrameOutput(CalculatorContext* cc) {
178
208
::mediapipe::Status TimeSeriesFramerCalculator::Process (CalculatorContext* cc) {
179
209
if (initial_input_timestamp_ == Timestamp::Unstarted ()) {
180
210
initial_input_timestamp_ = cc->InputTimestamp ();
211
+ current_timestamp_ = initial_input_timestamp_;
181
212
}
182
213
183
214
EnqueueInput (cc);
@@ -195,7 +226,8 @@ ::mediapipe::Status TimeSeriesFramerCalculator::Close(CalculatorContext* cc) {
195
226
std::unique_ptr<Matrix> output_frame (new Matrix);
196
227
output_frame->setZero (num_channels_, frame_duration_samples_);
197
228
for (int i = 0 ; i < sample_buffer_.size (); ++i) {
198
- output_frame->col (i) = sample_buffer_[i];
229
+ output_frame->col (i) = sample_buffer_[i].first ;
230
+ current_timestamp_ = sample_buffer_[i].second ;
199
231
}
200
232
201
233
cc->Outputs ().Index (0 ).Add (output_frame.release (),
@@ -258,6 +290,7 @@ ::mediapipe::Status TimeSeriesFramerCalculator::Open(CalculatorContext* cc) {
258
290
cumulative_output_frames_ = 0 ;
259
291
samples_still_to_drop_ = 0 ;
260
292
initial_input_timestamp_ = Timestamp::Unstarted ();
293
+ current_timestamp_ = Timestamp::Unstarted ();
261
294
262
295
std::vector<double > window_vector;
263
296
use_window_ = false ;
@@ -282,6 +315,7 @@ ::mediapipe::Status TimeSeriesFramerCalculator::Open(CalculatorContext* cc) {
282
315
frame_duration_samples_)
283
316
.cast <float >();
284
317
}
318
+ use_local_timestamp_ = framer_options.use_local_timestamp ();
285
319
286
320
return ::mediapipe::OkStatus ();
287
321
}
0 commit comments