#ifndef CLOUDPLAYERTHREAD_HPP #define CLOUDPLAYERTHREAD_HPP #include "ofMain.h" #include #include namespace ofxCloudLib { #define NUM_CLOUD_BUFFERS 4 class CloudPlayerThread : public ofThread { public: CloudPlayerThread() { octree_coder_ = new pcl::io::OctreePointCloudCompression( pcl::io::HIGH_RES_OFFLINE_COMPRESSION_WITH_COLOR, false, .01, .01, false, 1, 1, static_cast(4)); output_cloud_.reset(new pcl::PointCloud); } // ~CloudPlayerThread() // { // recorded_.close(); // waitForThread(true); // } bool setup(std::string playback_path) { playback_path_ = playback_path; if (ofDirectory::doesDirectoryExist(playback_path_)) { ofDirectory dir = ofDirectory(playback_path_); filename_ = playback_path_; is_setup_ = true; total_frames_ = dir.listDir(); decoded_frames_ = 0; ofLogNotice("CloudPlayerThread") << "will be playing " << total_frames_ << " frames from " << playback_path_; } else { ofLogError("CloudPlayerThread") << "no such directory: " << playback_path_; } return is_setup_; } size_t get_number_of_frames() { return total_frames_; } size_t get_current_frame() { return decoded_frames_; } void start() { decoded_frames_ = 0; startThread(); } pcl::PointCloud &get_cloud() { return cloud_[ready_cloud_buffer_]; } void update_cloud() { new_cloud_ = false; while (recorded_.tryReceive(cloud_[(ready_cloud_buffer_ + 1) % NUM_CLOUD_BUFFERS])) { new_cloud_ = true; ready_cloud_buffer_ = (ready_cloud_buffer_ + 1) % NUM_CLOUD_BUFFERS; } if (new_cloud_) { // ofLogNotice("CloudPlayerThread") << "safe cloud data with " << cloud_[ready_cloud_buffer_].size() << " points"; } } void update_mesh() { new_mesh_ = false; while (recorded_mesh_.tryReceive(mesh_[(ready_mesh_buffer_ + 1) % NUM_CLOUD_BUFFERS])) { new_mesh_ = true; ready_mesh_buffer_ = (ready_mesh_buffer_ + 1) % NUM_CLOUD_BUFFERS; } if (new_mesh_) { // ofLogNotice("CloudPlayerThread") << "safe mesh data with " << mesh_[ready_mesh_buffer_].getNumVertices() << " vertices"; } } bool is_cloud_new() { return new_cloud_; } bool is_mesh_new() { return new_mesh_; } ofMesh &get_mesh() { if (!isThreadRunning() && mesh_[ready_mesh_buffer_].getNumVertices()!=0) { mesh_[ready_mesh_buffer_].clear(); } return mesh_[ready_mesh_buffer_]; } float offset_x_ = 0; float offset_z_ = 0; void stop() { if (isThreadRunning()) { ofLogNotice("CloudPlayerThread") << "stopped_thread is now true"; stop_thread_ = true; } else { ofLogNotice("CloudPlayerThread") << "double-stop prevented"; } } std::string get_filename() { return filename_; } bool is_done_ = false; private: void threadedFunction() { ofLogNotice("CloudPlayerThread") << "thread started"; decodingFenceTimestamp = 0; while (1) { if (stop_thread_) { output_cloud_->clear(); ofMesh mesh; ofLogNotice("CloudPlayerThread") << "sending empty datasets before stopping"; recorded_.send(std::move(*output_cloud_)); recorded_mesh_.send(std::move(mesh)); // ofLogNotice("CloudPlayerThread") << "closing the channels"; // recorded_.close(); // recorded_mesh_.close(); ofLogNotice("CloudPlayerThread") << "stopping the thread"; stop_thread_ = false; new_cloud_ = false; stopThread(); ofLogNotice("CloudPlayerThread") << "thread stopped"; return; } auto sysnow = std::chrono::system_clock::now(); auto duration = sysnow.time_since_epoch(); uint64_t now = std::chrono::duration_cast(duration).count(); if (now > (decodingFenceTimestamp - ((1000. / 60.) / 2.))) { // devrait maintenir le modulo de la soustraction pour ne pas accumuler l'erreur (mais pas super grave) lastDecodingTimestamp = now; char filename_to_decode[100]; sprintf(filename_to_decode, "%s/cloud_%04i.pcd", playback_path_.c_str(), int(decoded_frames_++)); filename_ = std::string(filename_to_decode); ifstream cloudfile; cloudfile.open(filename_to_decode, ios::in | ios::binary); if (!cloudfile) { ofLogNotice("CloudPlayerThread") << filename_to_decode << " not found"; stop(); // stop_thread_ = true; // if looping.... is_done_ = true; decoded_frames_ = 0; } else { cloudfile.seekg(0); cloudfile.unsetf(ios_base::skipws); octree_coder_->decodePointCloud(cloudfile, output_cloud_); struct stat st; stat(filename_to_decode, &st); uint64_t status_ms = st.st_ctime * 1000 + st.st_ctim.tv_nsec / 1000000; if (previousCloudTimestamp == 0) { delay = 16; } else { delay = status_ms - previousCloudTimestamp; } delay = 50; previousCloudTimestamp = status_ms; decodingFenceTimestamp = now + delay; // ofLogNotice("CloudPlayerThread") << decoded_frames_ << " with " << output_cloud_->size() << " points from " << filename_to_decode << " with interval: " << delay; ofMesh mesh; for (unsigned int qq = 0; qq < output_cloud_->size(); qq++) { mesh.addVertex(ofPoint(output_cloud_->points[qq].x + offset_x_, output_cloud_->points[qq].y, output_cloud_->points[qq].z + offset_z_)); } recorded_.send(*output_cloud_); recorded_mesh_.send(mesh); // recorded_.send(std::move(*output_cloud_)); // recorded_mesh_.send(std::move(mesh)); } cloudfile.close(); } else { // std::cout << "DECODEUR: sleep" << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(2)); } // std::this_thread::sleep_for(std::chrono::milliseconds(2)); } } uint64_t lastDecodingTimestamp = 0; uint64_t previousCloudTimestamp = 0; uint64_t decodingFenceTimestamp = 0; uint64_t delay; std::string filename_; std::string playback_path_; bool new_mesh_ = false; bool new_cloud_ = false; bool is_setup_ = false; bool stop_thread_ = false; size_t decoded_frames_ = 0; size_t total_frames_ = 0; size_t ready_cloud_buffer_ = 0; size_t ready_mesh_buffer_ = 0; pcl::PointCloud::Ptr output_cloud_; ofMesh mesh_[NUM_CLOUD_BUFFERS]; pcl::PointCloud cloud_[NUM_CLOUD_BUFFERS]; pcl::io::OctreePointCloudCompression *octree_coder_; ofThreadChannel> recorded_; ofThreadChannel recorded_mesh_; }; } // namespace ofxCloudLib #endif // CLOUDPLAYERTHREAD_HPP