camera.cc 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. #include "tools/replay/camera.h"
  2. #include <cassert>
  3. #include <algorithm>
  4. #include <capnp/dynamic.h>
  5. #include "third_party/linux/include/msm_media_info.h"
  6. #include "tools/replay/util.h"
  7. const int BUFFER_COUNT = 40;
  8. std::tuple<size_t, size_t, size_t> get_nv12_info(int width, int height) {
  9. int nv12_width = VENUS_Y_STRIDE(COLOR_FMT_NV12, width);
  10. int nv12_height = VENUS_Y_SCANLINES(COLOR_FMT_NV12, height);
  11. assert(nv12_width == VENUS_UV_STRIDE(COLOR_FMT_NV12, width));
  12. assert(nv12_height / 2 == VENUS_UV_SCANLINES(COLOR_FMT_NV12, height));
  13. size_t nv12_buffer_size = 2346 * nv12_width; // comes from v4l2_format.fmt.pix_mp.plane_fmt[0].sizeimage
  14. return {nv12_width, nv12_height, nv12_buffer_size};
  15. }
  16. CameraServer::CameraServer(std::pair<int, int> camera_size[MAX_CAMERAS]) {
  17. for (int i = 0; i < MAX_CAMERAS; ++i) {
  18. std::tie(cameras_[i].width, cameras_[i].height) = camera_size[i];
  19. }
  20. startVipcServer();
  21. }
  22. CameraServer::~CameraServer() {
  23. for (auto &cam : cameras_) {
  24. if (cam.thread.joinable()) {
  25. // Clear the queue
  26. std::pair<FrameReader*, const Event *> item;
  27. while (cam.queue.try_pop(item)) {
  28. --publishing_;
  29. }
  30. // Signal termination and join the thread
  31. cam.queue.push({});
  32. cam.thread.join();
  33. }
  34. }
  35. vipc_server_.reset(nullptr);
  36. }
  37. void CameraServer::startVipcServer() {
  38. vipc_server_.reset(new VisionIpcServer("camerad"));
  39. for (auto &cam : cameras_) {
  40. cam.cached_buf.clear();
  41. if (cam.width > 0 && cam.height > 0) {
  42. rInfo("camera[%d] frame size %dx%d", cam.type, cam.width, cam.height);
  43. auto [nv12_width, nv12_height, nv12_buffer_size] = get_nv12_info(cam.width, cam.height);
  44. vipc_server_->create_buffers_with_sizes(cam.stream_type, BUFFER_COUNT, cam.width, cam.height,
  45. nv12_buffer_size, nv12_width, nv12_width * nv12_height);
  46. if (!cam.thread.joinable()) {
  47. cam.thread = std::thread(&CameraServer::cameraThread, this, std::ref(cam));
  48. }
  49. }
  50. }
  51. vipc_server_->start_listener();
  52. }
  53. void CameraServer::cameraThread(Camera &cam) {
  54. while (true) {
  55. const auto [fr, event] = cam.queue.pop();
  56. if (!fr) break;
  57. capnp::FlatArrayMessageReader reader(event->data);
  58. auto evt = reader.getRoot<cereal::Event>();
  59. auto eidx = capnp::AnyStruct::Reader(evt).getPointerSection()[0].getAs<cereal::EncodeIndex>();
  60. int segment_id = eidx.getSegmentId();
  61. uint32_t frame_id = eidx.getFrameId();
  62. if (auto yuv = getFrame(cam, fr, segment_id, frame_id)) {
  63. VisionIpcBufExtra extra = {
  64. .frame_id = frame_id,
  65. .timestamp_sof = eidx.getTimestampSof(),
  66. .timestamp_eof = eidx.getTimestampEof(),
  67. };
  68. vipc_server_->send(yuv, &extra);
  69. } else {
  70. rError("camera[%d] failed to get frame: %lu", cam.type, segment_id);
  71. }
  72. // Prefetch the next frame
  73. getFrame(cam, fr, segment_id + 1, frame_id + 1);
  74. --publishing_;
  75. }
  76. }
  77. VisionBuf *CameraServer::getFrame(Camera &cam, FrameReader *fr, int32_t segment_id, uint32_t frame_id) {
  78. // Check if the frame is cached
  79. auto buf_it = std::find_if(cam.cached_buf.begin(), cam.cached_buf.end(),
  80. [frame_id](VisionBuf *buf) { return buf->get_frame_id() == frame_id; });
  81. if (buf_it != cam.cached_buf.end()) return *buf_it;
  82. VisionBuf *yuv_buf = vipc_server_->get_buffer(cam.stream_type);
  83. if (fr->get(segment_id, yuv_buf)) {
  84. yuv_buf->set_frame_id(frame_id);
  85. cam.cached_buf.insert(yuv_buf);
  86. return yuv_buf;
  87. }
  88. return nullptr;
  89. }
  90. void CameraServer::pushFrame(CameraType type, FrameReader *fr, const Event *event) {
  91. auto &cam = cameras_[type];
  92. if (cam.width != fr->width || cam.height != fr->height) {
  93. cam.width = fr->width;
  94. cam.height = fr->height;
  95. waitForSent();
  96. startVipcServer();
  97. }
  98. ++publishing_;
  99. cam.queue.push({fr, event});
  100. }
  101. void CameraServer::waitForSent() {
  102. while (publishing_ > 0) {
  103. std::this_thread::yield();
  104. }
  105. }