rs-record-playback.cpp
Go to the documentation of this file.
1 // License: Apache 2.0. See LICENSE file in root directory.
2 // Copyright(c) 2017 Intel Corporation. All Rights Reserved.
3 
4 #include <librealsense2/rs.hpp> // Include RealSense Cross Platform API
5 #include "example.hpp" // Include short list of convenience functions for rendering
6 #include <chrono>
7 
8 #include <imgui.h>
9 #include "imgui_impl_glfw.h"
10 
11 // Includes for time display
12 #include <sstream>
13 #include <iostream>
14 #include <iomanip>
15 
16 
17 // Helper function for dispaying time conveniently
19 // Helper function for rendering a seek bar
20 void draw_seek_bar(rs2::playback& playback, int* seek_pos, float2& location, float width);
21 
22 int main(int argc, char * argv[]) try
23 {
24  // Create a simple OpenGL window for rendering:
25  window app(1280, 720, "RealSense Record and Playback Example");
26  ImGui_ImplGlfw_Init(app, false);
27 
28  // Create booleans to control GUI (recorded - allow play button, recording - show 'recording to file' text)
29  bool recorded = false;
30  bool recording = false;
31 
32  // Declare a texture for the depth image on the GPU
34 
35  // Declare frameset and frames which will hold the data from the camera
38 
39  // Declare depth colorizer for pretty visualization of depth data
40  rs2::colorizer color_map;
41 
42  // Create a shared pointer to a pipeline
43  auto pipe = std::make_shared<rs2::pipeline>();
44 
45  // Start streaming with default configuration
46  pipe->start();
47 
48  // Initialize a shared pointer to a device with the current device on the pipeline
49  rs2::device device = pipe->get_active_profile().get_device();
50 
51  // Create a variable to control the seek bar
52  int seek_pos;
53 
54  // While application is running
55  while(app) {
56  // Flags for displaying ImGui window
57  static const int flags = ImGuiWindowFlags_NoCollapse
63 
65  ImGui::SetNextWindowSize({ app.width(), app.height() });
66  ImGui::Begin("app", nullptr, flags);
67 
68  // If the device is sreaming live and not from a file
69  if (!device.as<rs2::playback>())
70  {
71  frames = pipe->wait_for_frames(); // wait for next set of frames from the camera
72  depth = color_map.process(frames.get_depth_frame()); // Find and colorize the depth data
73  }
74 
75  // Set options for the ImGui buttons
77  ImGui::PushStyleColor(ImGuiCol_Button, { 36 / 255.f, 44 / 255.f, 51 / 255.f, 1 });
78  ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 40 / 255.f, 170 / 255.f, 90 / 255.f, 1 });
79  ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 36 / 255.f, 44 / 255.f, 51 / 255.f, 1 });
81 
82  if (!device.as<rs2::playback>()) // Disable recording while device is playing
83  {
84  ImGui::SetCursorPos({ app.width() / 2 - 100, 3 * app.height() / 5 + 90});
85  ImGui::Text("Click 'record' to start recording");
86  ImGui::SetCursorPos({ app.width() / 2 - 100, 3 * app.height() / 5 + 110 });
87  if (ImGui::Button("record", { 50, 50 }))
88  {
89  // If it is the start of a new recording (device is not a recorder yet)
90  if (!device.as<rs2::recorder>())
91  {
92  pipe->stop(); // Stop the pipeline with the default configuration
93  pipe = std::make_shared<rs2::pipeline>();
94  rs2::config cfg; // Declare a new configuration
95  cfg.enable_record_to_file("a.bag");
96  pipe->start(cfg); //File will be opened at this point
97  device = pipe->get_active_profile().get_device();
98  }
99  else
100  { // If the recording is resumed after a pause, there's no need to reset the shared pointer
101  device.as<rs2::recorder>().resume(); // rs2::recorder allows access to 'resume' function
102  }
103  recording = true;
104  }
105 
106  /*
107  When pausing, device still holds the file.
108  */
109  if (device.as<rs2::recorder>())
110  {
111  if (recording)
112  {
113  ImGui::SetCursorPos({ app.width() / 2 - 100, 3 * app.height() / 5 + 60 });
114  ImGui::TextColored({ 255 / 255.f, 64 / 255.f, 54 / 255.f, 1 }, "Recording to file 'a.bag'");
115  }
116 
117  // Pause the playback if button is clicked
118  ImGui::SetCursorPos({ app.width() / 2, 3 * app.height() / 5 + 110 });
119  if (ImGui::Button("pause\nrecord", { 50, 50 }))
120  {
121  device.as<rs2::recorder>().pause();
122  recording = false;
123  }
124 
125  ImGui::SetCursorPos({ app.width() / 2 + 100, 3 * app.height() / 5 + 110 });
126  if (ImGui::Button(" stop\nrecord", { 50, 50 }))
127  {
128  pipe->stop(); // Stop the pipeline that holds the file and the recorder
129  pipe = std::make_shared<rs2::pipeline>(); //Reset the shared pointer with a new pipeline
130  pipe->start(); // Resume streaming with default configuration
131  device = pipe->get_active_profile().get_device();
132  recorded = true; // Now we can run the file
133  recording = false;
134  }
135  }
136  }
137 
138  // After a recording is done, we can play it
139  if (recorded) {
140  ImGui::SetCursorPos({ app.width() / 2 - 100, 4 * app.height() / 5 + 30 });
141  ImGui::Text("Click 'play' to start playing");
142  ImGui::SetCursorPos({ app.width() / 2 - 100, 4 * app.height() / 5 + 50});
143  if (ImGui::Button("play", { 50, 50 }))
144  {
145  if (!device.as<rs2::playback>())
146  {
147  pipe->stop(); // Stop streaming with default configuration
148  pipe = std::make_shared<rs2::pipeline>();
150  cfg.enable_device_from_file("a.bag");
151  pipe->start(cfg); //File will be opened in read mode at this point
152  device = pipe->get_active_profile().get_device();
153  }
154  else
155  {
156  device.as<rs2::playback>().resume();
157  }
158  }
159  }
160 
161  // If device is playing a recording, we allow pause and stop
162  if (device.as<rs2::playback>())
163  {
165  if (pipe->poll_for_frames(&frames)) // Check if new frames are ready
166  {
167  depth = color_map.process(frames.get_depth_frame()); // Find and colorize the depth data for rendering
168  }
169 
170  // Render a seek bar for the player
171  float2 location = { app.width() / 4, 4 * app.height() / 5 + 110 };
172  draw_seek_bar(playback , &seek_pos, location, app.width() / 2);
173 
174  ImGui::SetCursorPos({ app.width() / 2, 4 * app.height() / 5 + 50 });
175  if (ImGui::Button(" pause\nplaying", { 50, 50 }))
176  {
177  playback.pause();
178  }
179 
180  ImGui::SetCursorPos({ app.width() / 2 + 100, 4 * app.height() / 5 + 50 });
181  if (ImGui::Button(" stop\nplaying", { 50, 50 }))
182  {
183  pipe->stop();
184  pipe = std::make_shared<rs2::pipeline>();
185  pipe->start();
186  device = pipe->get_active_profile().get_device();
187  }
188  }
189 
192 
193  ImGui::End();
194  ImGui::Render();
195 
196  // Render depth frames from the default configuration, the recorder or the playback
197  depth_image.render(depth, { app.width() * 0.25f, app.height() * 0.25f, app.width() * 0.5f, app.height() * 0.75f });
198  }
199  return EXIT_SUCCESS;
200 }
201 catch (const rs2::error & e)
202 {
203  std::cout << "RealSense error calling " << e.get_failed_function() << "(" << e.get_failed_args() << "):\n " << e.what() << std::endl;
204  return EXIT_FAILURE;
205 }
206 catch (const std::exception& e)
207 {
208  std::cerr << e.what() << std::endl;
209  return EXIT_FAILURE;
210 }
211 
212 
214 {
215  using namespace std::chrono;
216  auto hhh = duration_cast<hours>(duration);
217  duration -= hhh;
218  auto mm = duration_cast<minutes>(duration);
219  duration -= mm;
220  auto ss = duration_cast<seconds>(duration);
221  duration -= ss;
222  auto ms = duration_cast<milliseconds>(duration);
223 
224  std::ostringstream stream;
225  stream << std::setfill('0') << std::setw(hhh.count() >= 10 ? 2 : 1) << hhh.count() << ':' <<
226  std::setfill('0') << std::setw(2) << mm.count() << ':' <<
227  std::setfill('0') << std::setw(2) << ss.count();
228  return stream.str();
229 }
230 
231 
232 void draw_seek_bar(rs2::playback& playback, int* seek_pos, float2& location, float width)
233 {
234  int64_t playback_total_duration = playback.get_duration().count();
235  auto progress = playback.get_position();
236  double part = (1.0 * progress) / playback_total_duration;
237  *seek_pos = static_cast<int>(std::max(0.0, std::min(part, 1.0)) * 100);
238  auto playback_status = playback.current_status();
239  ImGui::PushItemWidth(width);
240  ImGui::SetCursorPos({ location.x, location.y });
242  if (ImGui::SliderInt("##seek bar", seek_pos, 0, 100, "", true))
243  {
244  //Seek was dragged
245  if (playback_status != RS2_PLAYBACK_STATUS_STOPPED) //Ignore seek when playback is stopped
246  {
247  auto duration_db = std::chrono::duration_cast<std::chrono::duration<double, std::nano>>(playback.get_duration());
248  auto single_percent = duration_db.count() / 100;
249  auto seek_time = std::chrono::duration<double, std::nano>((*seek_pos) * single_percent);
250  playback.seek(std::chrono::duration_cast<std::chrono::nanoseconds>(seek_time));
251  }
252  }
254  ImGui::SetCursorPos({ location.x + width + 10, location.y });
255  ImGui::Text("%s", time_elapsed.c_str());
258 }
IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val)
Definition: imgui.cpp:4650
void seek(std::chrono::nanoseconds time)
void render(const rs2::frame &frame, const rect &rect, float alpha=1.f)
Definition: example.hpp:471
IMGUI_API void SetCursorPos(const ImVec2 &local_pos)
Definition: imgui.cpp:5094
float x
Definition: example.hpp:68
void draw_seek_bar(rs2::playback &playback, int *seek_pos, float2 &location, float width)
GLint location
def progress(args)
Definition: log.py:43
GLint GLint GLsizei GLsizei GLsizei depth
GLsizei const GLchar *const * string
GLuint GLuint stream
Definition: glext.h:1790
e
Definition: rmse.py:177
The texture class.
Definition: example.hpp:402
IMGUI_API bool SliderInt(const char *label, int *v, int v_min, int v_max, const char *display_format="%.0f", bool render_bg=false)
Definition: imgui.cpp:6687
depth_frame get_depth_frame() const
Definition: rs_frame.hpp:1006
const std::string & get_failed_args() const
Definition: rs_types.hpp:117
rs2::frame process(rs2::frame frame) const override
IMGUI_API bool Begin(const char *name, bool *p_open=NULL, ImGuiWindowFlags flags=0)
Definition: imgui.cpp:3772
int main(int argc, char *argv[])
IMGUI_API void PopStyleVar(int count=1)
Definition: imgui.cpp:4675
float y
Definition: example.hpp:68
std::ostream & cout()
float width() const
Definition: example.hpp:627
bool ImGui_ImplGlfw_Init(GLFWwindow *window, bool install_callbacks)
IMGUI_API void SetNextWindowSize(const ImVec2 &size, ImGuiSetCond cond=0)
Definition: imgui.cpp:4937
GLbitfield flags
IMGUI_API void PushItemWidth(float item_width)
Definition: imgui.cpp:4486
IMGUI_API void Text(const char *fmt,...) IM_PRINTFARGS(1)
Definition: imgui.cpp:5223
IMGUI_API bool Button(const char *label, const ImVec2 &size=ImVec2(0, 0))
Definition: imgui.cpp:5573
IMGUI_API void End()
Definition: imgui.cpp:4330
uint64_t get_position() const
IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4 &col)
Definition: imgui.cpp:4599
std::chrono::duration< uint64_t, std::nano > nanoseconds
float height() const
Definition: example.hpp:628
std::string pretty_time(std::chrono::nanoseconds duration)
void ImGui_ImplGlfw_NewFrame(float scale_factor)
IMGUI_API void PopItemWidth()
Definition: imgui.cpp:4507
rs2_playback_status current_status() const
int min(int a, int b)
Definition: lz4s.c:73
std::chrono::nanoseconds get_duration() const
signed __int64 int64_t
Definition: stdint.h:89
std::ostream & cerr()
static const textual_icon pause
Definition: model-views.h:224
auto device
Definition: pyrs_net.cpp:17
const std::string & get_failed_function() const
Definition: rs_types.hpp:112
GLint GLsizei width
IMGUI_API void Render()
Definition: imgui.cpp:2619
IMGUI_API void PopStyleColor(int count=1)
Definition: imgui.cpp:4609
T as() const
Definition: rs_device.hpp:129
IMGUI_API void TextColored(const ImVec4 &col, const char *fmt,...) IM_PRINTFARGS(2)
Definition: imgui.cpp:5238


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:47:40