image_encoder.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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. if (img->cv_type() == CV_8UC3) {
  50. // rgb -> bgra
  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. assert(img->cv_type() == CV_8UC4);
  58. } else {
  59. assert(img->pixel_format() == PIX_NV12);
  60. }
  61. assert(false); // TODO: fix this
  62. // auto frame = encoder->encode(img, enc_st.handle_idr());
  63. // return frame.data;
  64. }
  65. data_type encode(const image_ptr &img) {
  66. auto series = img->get_meta_ext<size_t>(META_SERIES_NAME);
  67. if (!enc_map.contains(series)) [[unlikely]] {
  68. enc_map.emplace(std::piecewise_construct,
  69. std::forward_as_tuple(series),
  70. std::forward_as_tuple(this));
  71. }
  72. auto enc_type = conf.type;
  73. size_t sp_id = 0;
  74. if (auto sp = img->get_meta_any(META_IMAGE_SPECIAL_CODEC); !sp.empty()) {
  75. enc_type = ENCODER_SPECIAL;
  76. sp_id = boost::any_cast<size_t>(sp);
  77. }
  78. auto head = json();
  79. head["series"] = series;
  80. head["type"] = enc_type;
  81. head["special"] = sp_id;
  82. head["width"] = img->width();
  83. head["height"] = img->height();
  84. head["pix_fmt"] = img->pixel_format();
  85. auto ret = data_type();
  86. switch (enc_type) {
  87. case ENCODER_NVENC: {
  88. ret = encode_nvenc(img, series);
  89. break;
  90. }
  91. case ENCODER_SPECIAL: {
  92. auto &enc_st = enc_map.at(series);
  93. ret = get_special_encoder(sp_id)(img, enc_st.handle_idr());
  94. break;
  95. }
  96. default: {
  97. RET_ERROR_E;
  98. }
  99. }
  100. auto writer = network_writer();
  101. writer.write_with_length(head);
  102. writer.write_with_length(ret);
  103. return writer.current_data();
  104. }
  105. };
  106. image_encoder::image_encoder(create_config conf)
  107. : pimpl(std::make_unique<impl>()) {
  108. pimpl->conf = conf;
  109. }
  110. image_encoder::~image_encoder() = default;
  111. data_type image_encoder::encode(const image_ptr &img) {
  112. return pimpl->encode(img);
  113. }
  114. void image_encoder::clear_cache() {
  115. pimpl->last_idr_req_ts = current_timestamp();
  116. }