encoder_related.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. #include "frame_encoder/encoder_jpeg.h"
  2. #include "frame_encoder/encoder_nvenc.h"
  3. #include "frame_sender/sender_base.h"
  4. #include "imgui_utility.h"
  5. #include "impl_types.h"
  6. #include "mvs_camera.h"
  7. #include "simple_mq.h"
  8. #include "variable_defs.h"
  9. #include "utility.hpp"
  10. #include <queue>
  11. using namespace simple_mq_singleton;
  12. bool encoder_save_file;
  13. bool encoder_save_length;
  14. encoder_type chosen_encoder = ENCODER_JPEG;
  15. nvenc_config main_nvenc_conf;
  16. nvjpeg_config main_nvjpeg_conf;
  17. std::unique_ptr<std::thread> encoder_thread;
  18. extern bool output_full_frame;
  19. extern bool output_halve_width;
  20. extern std::unique_ptr<smart_frame_buffer> output_fbo;
  21. extern sender_type chosen_sender;
  22. extern std::unique_ptr<sender_base> sender;
  23. extern mvs::capture_config capture_conf;
  24. extern std::unique_ptr<camera_related> left;
  25. extern std::unique_ptr<camera_related> right;
  26. extern std::queue<std::function<void()>> simple_eq;
  27. void load_encoder_config(YAML::Node conf) {
  28. mq().update_variable(OUTPUT_WIDTH, conf["width"].as<int>());
  29. mq().update_variable(OUTPUT_HEIGHT, conf["height"].as<int>());
  30. main_nvenc_conf.bitrate_mbps = conf["hevc_bitrate"].as<float>();
  31. main_nvjpeg_conf.quality = conf["jpeg_quality"].as<int>();
  32. }
  33. void encoder_thread_work() {
  34. uint64_t last_conf_cnt;
  35. std::unique_ptr<encoder_base> encoder;
  36. bool save_file = false;
  37. switch (chosen_encoder) {
  38. case ENCODER_NVENC: {
  39. auto conf = mq().query_variable<nvenc_config>(ENCODER_CONFIG, &last_conf_cnt);
  40. save_file = conf.save_file;
  41. encoder.reset(encoder_nvenc::create(conf));
  42. break;
  43. }
  44. case ENCODER_JPEG: {
  45. auto conf = mq().query_variable<nvjpeg_config>(ENCODER_CONFIG, &last_conf_cnt);
  46. save_file = conf.save_file;
  47. encoder.reset(encoder_jpeg::create(conf));
  48. break;
  49. }
  50. default: {
  51. RET_ERROR;
  52. }
  53. }
  54. uint64_t frame_cnt = 0;
  55. for (;;) {
  56. mq().wait_variable(OUTPUT_FRAME, frame_cnt);
  57. auto frame = mq().query_variable_ptr<cv::cuda::GpuMat>(OUTPUT_FRAME, &frame_cnt);
  58. // test stop flag
  59. if (mq().query_variable<bool>(ENCODER_SHOULD_STOP)) break;
  60. if (!(save_file ||
  61. mq().query_variable<bool>(SENDER_CONNECTED))) {
  62. continue; // no need to encode frame
  63. }
  64. // check for config update
  65. uint64_t cur_conf_cnt;
  66. switch (chosen_encoder) {
  67. case ENCODER_NVENC: {
  68. auto conf = mq().query_variable<nvenc_config>(ENCODER_CONFIG, &cur_conf_cnt);
  69. if (cur_conf_cnt > last_conf_cnt) {
  70. auto real_encoder = dynamic_cast<encoder_nvenc *>(encoder.get());
  71. assert(real_encoder != nullptr);
  72. real_encoder->change_config(conf);
  73. last_conf_cnt = cur_conf_cnt;
  74. }
  75. break;
  76. }
  77. case ENCODER_JPEG: {
  78. auto conf = mq().query_variable<nvjpeg_config>(ENCODER_CONFIG, &cur_conf_cnt);
  79. if (cur_conf_cnt > last_conf_cnt) {
  80. auto real_encoder = dynamic_cast<encoder_jpeg *>(encoder.get());
  81. assert(real_encoder != nullptr);
  82. real_encoder->change_config(conf);
  83. last_conf_cnt = cur_conf_cnt;
  84. }
  85. break;
  86. }
  87. default : {
  88. RET_ERROR;
  89. }
  90. }
  91. bool force_idr = false;
  92. if (mq().query_variable<bool>(REQUEST_IDR)) {
  93. force_idr = true;
  94. mq().update_variable(REQUEST_IDR, false);
  95. }
  96. if (frame == nullptr) continue;
  97. auto frame_data = std::make_unique<video_nal>();
  98. encoder->encode(*frame, frame_data.get(), force_idr);
  99. if (mq().query_variable<bool>(SENDER_CONNECTED)) {
  100. assert(sender != nullptr);
  101. sender->send_frame(std::move(frame_data));
  102. }
  103. }
  104. }
  105. bool is_encoding() {
  106. return encoder_thread != nullptr;
  107. }
  108. void upload_encoder_config() {
  109. switch (chosen_encoder) {
  110. case ENCODER_NVENC: {
  111. main_nvenc_conf.save_file = encoder_save_file;
  112. main_nvenc_conf.save_length = encoder_save_length;
  113. mq().update_variable(ENCODER_CONFIG, main_nvenc_conf);
  114. break;
  115. }
  116. case ENCODER_JPEG: {
  117. main_nvjpeg_conf.save_file = encoder_save_file;
  118. main_nvjpeg_conf.save_length = encoder_save_length;
  119. mq().update_variable(ENCODER_CONFIG, main_nvjpeg_conf);
  120. break;
  121. }
  122. default: {
  123. RET_ERROR;
  124. }
  125. }
  126. }
  127. void start_encoder() {
  128. // determine output frame size
  129. cv::Size frame_size;
  130. if (output_full_frame) {
  131. assert(!left->img_dev.empty() && !right->img_dev.empty());
  132. assert(left->img_dev.size() == right->img_dev.size());
  133. frame_size.width = left->img_dev.size().width * 2;
  134. frame_size.height = left->img_dev.size().height;
  135. } else {
  136. frame_size = {mq().query_variable<int>(OUTPUT_WIDTH),
  137. mq().query_variable<int>(OUTPUT_HEIGHT)};
  138. }
  139. output_fbo->create(frame_size);
  140. // update config
  141. switch (chosen_encoder) {
  142. case ENCODER_NVENC: {
  143. main_nvenc_conf.frame_size = frame_size;
  144. main_nvenc_conf.frame_rate = capture_conf.frame_rate;
  145. break;
  146. }
  147. case ENCODER_JPEG: {
  148. break;
  149. }
  150. default: {
  151. RET_ERROR;
  152. }
  153. }
  154. upload_encoder_config();
  155. mq().update_variable(ENCODER_SHOULD_STOP, false);
  156. mq().update_variable(ENCODER_BUSY, false); // make variable exist
  157. encoder_thread = std::make_unique<std::thread>(encoder_thread_work);
  158. }
  159. void stop_encoder() {
  160. if (encoder_thread == nullptr) return;
  161. mq().update_variable(ENCODER_SHOULD_STOP, true);
  162. mq().update_variable_ptr<cv::cuda::GpuMat>(OUTPUT_FRAME, nullptr);
  163. encoder_thread->join();
  164. encoder_thread.reset();
  165. }
  166. void show_encoder_ui() {
  167. ImGui::SeparatorText("Method");
  168. {
  169. auto guard = imgui_disable_guard{is_encoding()};
  170. if (ImGui::RadioButton("NvEnc", chosen_encoder == ENCODER_NVENC)) {
  171. simple_eq.emplace([] {
  172. chosen_encoder = ENCODER_NVENC;
  173. if (chosen_sender == SENDER_UDP) { // NvEnc cannot be used with UDP
  174. chosen_sender = SENDER_TCP;
  175. }
  176. });
  177. }
  178. ImGui::SameLine();
  179. if (ImGui::RadioButton("nvJPEG", chosen_encoder == ENCODER_JPEG)) {
  180. simple_eq.emplace([] { chosen_encoder = ENCODER_JPEG; });
  181. }
  182. }
  183. ImGui::SeparatorText("Actions");
  184. if (!is_encoding()) {
  185. if (ImGui::Button("Start")) {
  186. simple_eq.emplace(start_encoder);
  187. }
  188. } else {
  189. if (ImGui::Button("Close")) {
  190. simple_eq.emplace(stop_encoder);
  191. }
  192. ImGui::SameLine();
  193. if (ImGui::Button("Request IDR")) {
  194. simple_eq.emplace([] { mq().update_variable(REQUEST_IDR, true); });
  195. }
  196. }
  197. ImGui::SeparatorText("Configs");
  198. switch (chosen_encoder) {
  199. case ENCODER_NVENC: {
  200. if (ImGui::DragFloat("Bitrate (Mbps)", &main_nvenc_conf.bitrate_mbps,
  201. 0.1, 1, 20, "%.01f")) {
  202. simple_eq.emplace(upload_encoder_config);
  203. }
  204. break;
  205. }
  206. case ENCODER_JPEG: {
  207. if (ImGui::DragInt("Quality (%)", &main_nvjpeg_conf.quality, 1, 1, 100)) {
  208. simple_eq.emplace(upload_encoder_config);
  209. }
  210. break;
  211. }
  212. default: {
  213. RET_ERROR;
  214. }
  215. }
  216. {
  217. auto guard = imgui_disable_guard{is_encoding()};
  218. ImGui::Checkbox("Full Resolution", &output_full_frame);
  219. if (!output_full_frame) {
  220. ImGui::SameLine();
  221. ImGui::Checkbox("Halve Width", &output_halve_width);
  222. }
  223. // ImGui::SameLine();
  224. ImGui::Checkbox("Save Video", &encoder_save_file);
  225. if (encoder_save_file) {
  226. ImGui::SameLine();
  227. ImGui::Checkbox("Save Frame Length", &encoder_save_length);
  228. }
  229. }
  230. }