SLProject  4.3.020
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
SENSRecorderDataHandler.cpp
Go to the documentation of this file.
2 #include <HighResTimer.h>
3 //-----------------------------------------------------------------------------
4 template<typename T>
6  : _name(name)
7 {
8 }
9 
10 template<typename T>
12 {
13  stop();
14 }
15 
16 template<typename T>
17 void SENSRecorderDataHandler<T>::start(const std::string& outputDir)
18 {
19  stop();
20  //start writer thread
21  _errorMsg.clear();
22  _outputDir = outputDir;
23  _thread = std::thread(&SENSRecorderDataHandler::store, this);
24 }
25 
26 template<typename T>
28 {
29  std::unique_lock<std::mutex> lock(_mutex);
30  _stop = true;
31  lock.unlock();
32  _condVar.notify_one();
33 
34  if (_thread.joinable())
35  _thread.join();
36 
37  lock.lock();
38  _queue.clear();
39  _stop = false;
40 }
41 
42 template<typename T>
44 {
45  SENS_DEBUG("SENSRecorderDataHandler: starting store");
46  writeOnThreadStart();
47  //open file
48  std::string fileName = _outputDir + _name + ".txt";
49  ofstream file;
50  file.open(fileName);
51  if (file.is_open())
52  {
53  writeHeaderToFile(file);
54  while (true)
55  {
56  std::unique_lock<std::mutex> lock(_mutex);
57 
58  _condVar.wait(lock, [&]
59  { return (_stop == true || _queue.size() != 0); });
60  if (_stop)
61  break;
62 
63  SENS_DEBUG("SENSRecorderDataHandler: queue size: %d", _queue.size());
64 
65  std::deque<T> localQueue;
66  while (_queue.size())
67  {
68  localQueue.push_back(_queue.front());
69  _queue.pop_front();
70  }
71 
72  lock.unlock();
73 
74  //write data
75  if (localQueue.size())
76  {
77  writeLineToFile(file, localQueue.front());
78  localQueue.pop_front();
79  }
80 
81  if (localQueue.size())
82  {
83  std::stringstream ss;
84  ss << "Data writing is too slow. Skipping " << localQueue.size() << " values from queue!";
85  SENS_WARN("SENSRecorderDataHandler store: %s", ss.str().c_str());
86  //if buffer is running full, warn and skip values
87  {
88  std::lock_guard<std::mutex> lock(_msgMutex);
89  _errorMsg = ss.str();
90  }
91  localQueue.clear();
92  }
93  }
94  }
95  writeOnThreadFinish();
96  //close file
97  file.close();
98 }
99 
100 template<typename T>
102 {
103  std::unique_lock<std::mutex> lock(_mutex);
104  _queue.push_back(std::move(item));
105  lock.unlock();
106  _condVar.notify_one();
107 }
108 
109 template<typename T>
111 {
112  std::lock_guard<std::mutex> lock(_msgMutex);
113  if (_errorMsg.empty())
114  return false;
115  else
116  {
117  msg = _errorMsg;
118  return true;
119  }
120 }
121 
122 //explicit instantiation
123 template class SENSRecorderDataHandler<GpsInfo>;
126 
127 //-----------------------------------------------------------------------------
129  : SENSRecorderDataHandler("gps")
130 {
131 }
132 
133 void SENSGpsRecorderDataHandler::writeLineToFile(ofstream& file, const GpsInfo& data)
134 {
135  file << std::chrono::time_point_cast<SENSMicroseconds>(data.second).time_since_epoch().count() << " "
136  << data.first.latitudeDEG << " "
137  << data.first.longitudeDEG << " "
138  << data.first.altitudeM << " "
139  << data.first.accuracyM << "\n";
140 }
141 
142 //-----------------------------------------------------------------------------
144  : SENSRecorderDataHandler("orientation")
145 {
146 }
147 
149 {
150  //reading (https://stackoverflow.com/questions/31255486/c-how-do-i-convert-a-stdchronotime-point-to-long-and-back)
151  //long readTimePt;
152  //microseconds readTimePtUs(readTimePt);
153  //time_point<high_resolution_clock> dt(readTimePt);
154 
155  file << std::chrono::time_point_cast<SENSMicroseconds>(data.second).time_since_epoch().count() << " "
156  << data.first.quatX << " "
157  << data.first.quatY << " "
158  << data.first.quatZ << " "
159  << data.first.quatW << "\n";
160 }
161 
162 //-----------------------------------------------------------------------------
164  : SENSRecorderDataHandler("camera")
165 {
166 }
167 
169 {
170  _frameIndex = 0;
171 }
172 
174 {
175  if (data.first.empty())
176  {
177  SENS_WARN("SENSCameraRecorderDataHandler::writeLineToFile: frame is empty");
178  return;
179  }
180 
181  if (!_videoWriter.isOpened())
182  {
183  std::string filename = _outputDir + "video.avi";
184  _videoWriter.open(filename, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'), 30, data.first.size(), true);
185  //_videoWriter.open(filename, cv::VideoWriter::fourcc('X', 'V', 'I', 'D'), 30, data.first.size(), true);
186  SENS_DEBUG("Opening video for writing: %s", filename.c_str());
187  }
188 
189  if (!_videoWriter.isOpened())
190  {
191  SENS_WARN("SENSCameraRecorderDataHandler::writeLineToFile: video writer not opened");
192  }
193  else
194  {
195  long long timePt = std::chrono::time_point_cast<SENSMicroseconds>(data.second).time_since_epoch().count();
196  //write time and frame index
197  file << timePt << " " << _frameIndex << "\n";
198  //SENS_DEBUG("SENSCameraRecorderDataHandler: time point for frame %d is %s", _frameIndex, timeStr.c_str());
199  _frameIndex++;
200 
201  _videoWriter.write(data.first);
202  }
203 }
204 
206 {
207  if (_videoWriter.isOpened())
208  _videoWriter.release();
209 }
210 
212 {
213  //write config to file in directory
214  std::string fileName = _outputDir + "cameraConfig.json";
215  if (Utils::fileExists(fileName))
216  Utils::removeFile(fileName);
217 
218  cv::FileStorage fs;
219  fs.open(fileName, cv::FileStorage::WRITE);
220  if (fs.isOpened())
221  {
222  fs << "deviceId" << config.deviceId;
223  fs << "widthPix" << config.streamConfig.widthPix;
224  fs << "heightPix" << config.streamConfig.heightPix;
225  fs << "focalLengthPix" << config.streamConfig.focalLengthPix;
226  fs << "focusMode" << (int)config.focusMode;
227  fs << "facing" << (int)config.facing;
228  }
229 }
#define SENS_DEBUG(...)
Definition: SENS.h:60
#define SENS_WARN(...)
Definition: SENS.h:64
std::pair< SENSOrientation::Quat, SENSTimePt > OrientationInfo
std::pair< SENSGps::Location, SENSTimePt > GpsInfo
std::pair< cv::Mat, SENSTimePt > FrameInfo
void updateConfig(const SENSCameraConfig &config)
void writeLineToFile(ofstream &file, const FrameInfo &data) override
called in thread store routine for every new line
void writeOnThreadFinish() override
called in thread store routine when thread finished
void writeOnThreadStart() override
called in thread store routine when thread starts
void writeLineToFile(ofstream &file, const GpsInfo &data) override
called in thread store routine for every new line
void writeLineToFile(ofstream &file, const OrientationInfo &data) override
called in thread store routine for every new line
void add(T &&item)
add new value to store queue
SENSRecorderDataHandler(const std::string &name)
bool getErrorMsg(std::string &msg)
get error msg (valid if function returns true)
void stop()
stop the store thread and clear values in queue
void start(const std::string &outputDir)
start the store thread
Config config
The configuration set in App::run.
Definition: AppAndroid.cpp:34
bool fileExists(const string &pathfilename)
Returns true if a file exists.
Definition: Utils.cpp:894
void removeFile(const string &path)
RemoveFile deletes a file with given path.
Definition: Utils.cpp:872