image_encoder.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #include "image_encoder.h"
  2. #include "image_codec.h"
  3. #include "codec/encoder_nvenc.h"
  4. #include "image_process/cuda_impl/pixel_convert.cuh"
  5. #include <nlohmann/json.hpp>
  6. using namespace nlohmann;
  7. using namespace image_codec;
  8. struct image_encoder::impl {
  9. create_config conf;
  10. struct encoder_store_type {
  11. impl *pimpl = nullptr;
  12. std::unique_ptr<encoder_nvenc> nvenc;
  13. timestamp_type last_clear_ts = 0;
  14. bool handle_idr() {
  15. if (auto req_ts = pimpl->last_idr_req_ts;
  16. last_clear_ts < pimpl->last_idr_req_ts) {
  17. last_clear_ts = req_ts;
  18. return true;
  19. }
  20. return false;
  21. }
  22. };
  23. using encoder_map_type =
  24. std::unordered_map<size_t, encoder_store_type>;
  25. encoder_map_type enc_map;
  26. timestamp_type last_idr_req_ts = current_timestamp();
  27. data_type encode_nvenc(image_ptr img, size_t series) {
  28. // create NvEnc if needed
  29. assert(enc_map.contains(series));
  30. auto &enc_st = enc_map.at(series);
  31. auto &encoder = enc_st.nvenc;
  32. auto img_size = img->size();
  33. if (encoder == nullptr
  34. || encoder->frame_size() != img_size) [[unlikely]] {
  35. auto fps = img->get_meta_ext<size_t>(META_REFRESH_RATE);
  36. auto enc_conf = encoder_nvenc::create_config{
  37. .frame_size = img_size,
  38. .frame_rate = (int) fps,
  39. .bitrate_mbps = conf.bitrate_mbps,
  40. .save_file = conf.save_file,
  41. .save_length = conf.save_length,
  42. .ctx = conf.ctx,
  43. .stream = conf.stream,
  44. };
  45. encoder = encoder_nvenc::create(enc_conf);
  46. }
  47. assert(encoder != nullptr);
  48. assert(encoder->frame_size() == img_size);
  49. // rgb -> bgra
  50. if (img->cv_type() == CV_8UC3) {
  51. auto img_bgra = create_image(img_size, CV_8UC4);
  52. call_cvt_rgb_bgra_u8(img->cuda<uchar3>(conf.stream),
  53. img_bgra->cuda<uchar4>(conf.stream),
  54. conf.stream->cuda);
  55. img_bgra->cuda_modified(conf.stream);
  56. img = img_bgra;
  57. }
  58. assert(img->cv_type() == CV_8UC4);
  59. auto frame = encoder->encode(img->v1<uchar4>(), enc_st.handle_idr());
  60. return frame.data;
  61. }
  62. data_type encode(const image_ptr &img) {
  63. auto series = img->get_meta_ext<size_t>(META_SERIES_NAME);
  64. if (!enc_map.contains(series)) [[unlikely]] {
  65. enc_map.emplace(std::piecewise_construct,
  66. std::forward_as_tuple(series),
  67. std::forward_as_tuple(this));
  68. }
  69. auto enc_type = conf.type;
  70. size_t sp_id = 0;
  71. if (auto sp = img->get_meta_any(META_IMAGE_SPECIAL_CODEC); !sp.empty()) {
  72. enc_type = ENCODER_SPECIAL;
  73. sp_id = boost::any_cast<size_t>(sp);
  74. }
  75. auto head = json();
  76. head["series"] = series;
  77. head["type"] = enc_type;
  78. head["special"] = sp_id;
  79. head["width"] = img->width();
  80. head["height"] = img->height();
  81. auto ret = data_type();
  82. switch (enc_type) {
  83. case ENCODER_NVENC: {
  84. ret = encode_nvenc(img, series);
  85. break;
  86. }
  87. case ENCODER_SPECIAL: {
  88. auto &enc_st = enc_map.at(series);
  89. ret = get_special_encoder(sp_id)(img, enc_st.handle_idr());
  90. break;
  91. }
  92. default: {
  93. RET_ERROR_E;
  94. }
  95. }
  96. auto writer = network_writer();
  97. writer.write_with_length(head);
  98. writer.write_with_length(ret);
  99. return writer.current_data();
  100. }
  101. };
  102. image_encoder::image_encoder(create_config conf)
  103. : pimpl(std::make_unique<impl>()) {
  104. pimpl->conf = conf;
  105. }
  106. image_encoder::~image_encoder() = default;
  107. data_type image_encoder::encode(const image_ptr &img) {
  108. return pimpl->encode(img);
  109. }
  110. void image_encoder::clear_cache() {
  111. pimpl->last_idr_req_ts = current_timestamp();
  112. }