You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							350 lines
						
					
					
						
							9.2 KiB
						
					
					
				
			
		
		
	
	
							350 lines
						
					
					
						
							9.2 KiB
						
					
					
				#include <thread>
 | 
						|
#include <stdio.h>
 | 
						|
#include <signal.h>
 | 
						|
#include <poll.h>
 | 
						|
#include <assert.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <sys/socket.h>
 | 
						|
 | 
						|
#if defined(QCOM) && !defined(QCOM_REPLAY)
 | 
						|
#include "cameras/camera_qcom.h"
 | 
						|
#elif QCOM2
 | 
						|
#include "cameras/camera_qcom2.h"
 | 
						|
#elif WEBCAM
 | 
						|
#include "cameras/camera_webcam.h"
 | 
						|
#else
 | 
						|
#include "cameras/camera_frame_stream.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#include <libyuv.h>
 | 
						|
 | 
						|
#include "clutil.h"
 | 
						|
#include "common/ipc.h"
 | 
						|
#include "common/params.h"
 | 
						|
#include "common/swaglog.h"
 | 
						|
#include "common/util.h"
 | 
						|
#include "common/visionipc.h"
 | 
						|
 | 
						|
#define MAX_CLIENTS 6
 | 
						|
 | 
						|
volatile sig_atomic_t do_exit = 0;
 | 
						|
 | 
						|
static void set_do_exit(int sig) {
 | 
						|
  do_exit = 1;
 | 
						|
}
 | 
						|
 | 
						|
struct VisionState;
 | 
						|
 | 
						|
struct VisionClientState {
 | 
						|
  VisionState *s;
 | 
						|
  int fd;
 | 
						|
  pthread_t thread_handle;
 | 
						|
  bool running;
 | 
						|
};
 | 
						|
 | 
						|
struct VisionClientStreamState {
 | 
						|
  bool subscribed;
 | 
						|
  int bufs_outstanding;
 | 
						|
  bool tb;
 | 
						|
  TBuffer* tbuffer;
 | 
						|
  PoolQueue* queue;
 | 
						|
};
 | 
						|
 | 
						|
struct VisionState {
 | 
						|
  MultiCameraState cameras;
 | 
						|
  pthread_mutex_t clients_lock;
 | 
						|
  VisionClientState clients[MAX_CLIENTS];
 | 
						|
};
 | 
						|
 | 
						|
static CameraBuf *get_camerabuf_by_type(VisionState *s, VisionStreamType type) {
 | 
						|
  assert(type >= 0 && type < VISION_STREAM_MAX);
 | 
						|
  if (type == VISION_STREAM_RGB_BACK || type == VISION_STREAM_YUV) {
 | 
						|
    return &s->cameras.rear.buf;
 | 
						|
  } else if (type == VISION_STREAM_RGB_FRONT || type == VISION_STREAM_YUV_FRONT) {
 | 
						|
    return &s->cameras.front.buf;
 | 
						|
  }
 | 
						|
#ifdef QCOM2
 | 
						|
  return &s->cameras.wide.buf;
 | 
						|
#endif
 | 
						|
  assert(0);
 | 
						|
}
 | 
						|
 | 
						|
// visionserver
 | 
						|
void* visionserver_client_thread(void* arg) {
 | 
						|
  int err;
 | 
						|
  VisionClientState *client = (VisionClientState*)arg;
 | 
						|
  VisionState *s = client->s;
 | 
						|
  int fd = client->fd;
 | 
						|
 | 
						|
  set_thread_name("clientthread");
 | 
						|
 | 
						|
  VisionClientStreamState streams[VISION_STREAM_MAX] = {{0}};
 | 
						|
 | 
						|
  LOGW("client start fd %d", fd);
 | 
						|
 | 
						|
  while (true) {
 | 
						|
    struct pollfd polls[1+VISION_STREAM_MAX] = {{0}};
 | 
						|
    polls[0].fd = fd;
 | 
						|
    polls[0].events = POLLIN;
 | 
						|
 | 
						|
    int poll_to_stream[1+VISION_STREAM_MAX] = {0};
 | 
						|
    int num_polls = 1;
 | 
						|
    for (int i=0; i<VISION_STREAM_MAX; i++) {
 | 
						|
      if (!streams[i].subscribed) continue;
 | 
						|
      polls[num_polls].events = POLLIN;
 | 
						|
      if (streams[i].bufs_outstanding >= 2) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      if (streams[i].tb) {
 | 
						|
        polls[num_polls].fd = tbuffer_efd(streams[i].tbuffer);
 | 
						|
      } else {
 | 
						|
        polls[num_polls].fd = poolq_efd(streams[i].queue);
 | 
						|
      }
 | 
						|
      poll_to_stream[num_polls] = i;
 | 
						|
      num_polls++;
 | 
						|
    }
 | 
						|
    int ret = poll(polls, num_polls, -1);
 | 
						|
    if (ret < 0) {
 | 
						|
      if (errno == EINTR || errno == EAGAIN) continue;
 | 
						|
      LOGE("poll failed (%d - %d)", ret, errno);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    if (do_exit) break;
 | 
						|
    if (polls[0].revents) {
 | 
						|
      VisionPacket p;
 | 
						|
      err = vipc_recv(fd, &p);
 | 
						|
      if (err <= 0) {
 | 
						|
        break;
 | 
						|
      } else if (p.type == VIPC_STREAM_SUBSCRIBE) {
 | 
						|
        VisionStreamType stream_type = p.d.stream_sub.type;
 | 
						|
        VisionPacket rep = {
 | 
						|
          .type = VIPC_STREAM_BUFS,
 | 
						|
          .d = { .stream_bufs = { .type = stream_type }, },
 | 
						|
        };
 | 
						|
 | 
						|
        VisionClientStreamState *stream = &streams[stream_type];
 | 
						|
        stream->tb = p.d.stream_sub.tbuffer;
 | 
						|
 | 
						|
        VisionStreamBufs *stream_bufs = &rep.d.stream_bufs;
 | 
						|
        CameraBuf *b = get_camerabuf_by_type(s, stream_type);
 | 
						|
        if (stream_type == VISION_STREAM_RGB_BACK ||
 | 
						|
            stream_type == VISION_STREAM_RGB_FRONT ||
 | 
						|
            stream_type == VISION_STREAM_RGB_WIDE) {
 | 
						|
          stream_bufs->width = b->rgb_width;
 | 
						|
          stream_bufs->height = b->rgb_height;
 | 
						|
          stream_bufs->stride = b->rgb_stride;
 | 
						|
          stream_bufs->buf_len = b->rgb_bufs[0].len;
 | 
						|
          rep.num_fds = UI_BUF_COUNT;
 | 
						|
          for (int i = 0; i < rep.num_fds; i++) {
 | 
						|
            rep.fds[i] = b->rgb_bufs[i].fd;
 | 
						|
          }
 | 
						|
          if (stream->tb) {
 | 
						|
            stream->tbuffer = &b->ui_tb;
 | 
						|
          } else {
 | 
						|
            assert(false);
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          stream_bufs->width = b->yuv_width;
 | 
						|
          stream_bufs->height = b->yuv_height;
 | 
						|
          stream_bufs->stride = b->yuv_width;
 | 
						|
          stream_bufs->buf_len = b->yuv_buf_size;
 | 
						|
          rep.num_fds = YUV_COUNT;
 | 
						|
          for (int i = 0; i < rep.num_fds; i++) {
 | 
						|
            rep.fds[i] = b->yuv_ion[i].fd;
 | 
						|
          }
 | 
						|
          if (stream->tb) {
 | 
						|
            stream->tbuffer = b->yuv_tb;
 | 
						|
          } else {
 | 
						|
            stream->queue = pool_get_queue(&b->yuv_pool);
 | 
						|
          }
 | 
						|
        }
 | 
						|
        vipc_send(fd, &rep);
 | 
						|
        streams[stream_type].subscribed = true;
 | 
						|
      } else if (p.type == VIPC_STREAM_RELEASE) {
 | 
						|
        int si = p.d.stream_rel.type;
 | 
						|
        assert(si < VISION_STREAM_MAX);
 | 
						|
        if (streams[si].tb) {
 | 
						|
          tbuffer_release(streams[si].tbuffer, p.d.stream_rel.idx);
 | 
						|
        } else {
 | 
						|
          poolq_release(streams[si].queue, p.d.stream_rel.idx);
 | 
						|
        }
 | 
						|
        streams[p.d.stream_rel.type].bufs_outstanding--;
 | 
						|
      } else {
 | 
						|
        assert(false);
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      int stream_i = VISION_STREAM_MAX;
 | 
						|
      for (int i=1; i<num_polls; i++) {
 | 
						|
        int si = poll_to_stream[i];
 | 
						|
        if (!streams[si].subscribed) continue;
 | 
						|
        if (polls[i].revents) {
 | 
						|
          stream_i = si;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if (stream_i < VISION_STREAM_MAX) {
 | 
						|
        streams[stream_i].bufs_outstanding++;
 | 
						|
        int idx;
 | 
						|
        if (streams[stream_i].tb) {
 | 
						|
          idx = tbuffer_acquire(streams[stream_i].tbuffer);
 | 
						|
        } else {
 | 
						|
          idx = poolq_pop(streams[stream_i].queue);
 | 
						|
        }
 | 
						|
        if (idx < 0) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        VisionPacket rep = {
 | 
						|
          .type = VIPC_STREAM_ACQUIRE,
 | 
						|
          .d = {.stream_acq = {
 | 
						|
            .type = (VisionStreamType)stream_i,
 | 
						|
            .idx = idx,
 | 
						|
          }},
 | 
						|
        };
 | 
						|
        if (stream_i == VISION_STREAM_YUV ||
 | 
						|
            stream_i == VISION_STREAM_YUV_FRONT ||
 | 
						|
            stream_i == VISION_STREAM_YUV_WIDE) {
 | 
						|
          CameraBuf *b = get_camerabuf_by_type(s, (VisionStreamType)stream_i);
 | 
						|
          rep.d.stream_acq.extra.frame_id = b->yuv_metas[idx].frame_id;
 | 
						|
          rep.d.stream_acq.extra.timestamp_sof = b->yuv_metas[idx].timestamp_sof;
 | 
						|
          rep.d.stream_acq.extra.timestamp_eof = b->yuv_metas[idx].timestamp_eof;
 | 
						|
        }
 | 
						|
        vipc_send(fd, &rep);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  LOGW("client end fd %d", fd);
 | 
						|
 | 
						|
  for (int i=0; i<VISION_STREAM_MAX; i++) {
 | 
						|
    if (!streams[i].subscribed) continue;
 | 
						|
    if (streams[i].tb) {
 | 
						|
      tbuffer_release_all(streams[i].tbuffer);
 | 
						|
    } else {
 | 
						|
      pool_release_queue(streams[i].queue);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  close(fd);
 | 
						|
 | 
						|
  pthread_mutex_lock(&s->clients_lock);
 | 
						|
  client->running = false;
 | 
						|
  pthread_mutex_unlock(&s->clients_lock);
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
void* visionserver_thread(void* arg) {
 | 
						|
  int err;
 | 
						|
  VisionState *s = (VisionState*)arg;
 | 
						|
 | 
						|
  set_thread_name("visionserver");
 | 
						|
 | 
						|
  int sock = ipc_bind(VIPC_SOCKET_PATH);
 | 
						|
  while (!do_exit) {
 | 
						|
    struct pollfd polls[1] = {{0}};
 | 
						|
    polls[0].fd = sock;
 | 
						|
    polls[0].events = POLLIN;
 | 
						|
 | 
						|
    int ret = poll(polls, ARRAYSIZE(polls), 1000);
 | 
						|
    if (ret < 0) {
 | 
						|
      if (errno == EINTR || errno == EAGAIN) continue;
 | 
						|
      LOGE("poll failed (%d - %d)", ret, errno);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    if (do_exit) break;
 | 
						|
    if (!polls[0].revents) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    int fd = accept(sock, NULL, NULL);
 | 
						|
    assert(fd >= 0);
 | 
						|
 | 
						|
    pthread_mutex_lock(&s->clients_lock);
 | 
						|
 | 
						|
    int client_idx = 0;
 | 
						|
    for (; client_idx < MAX_CLIENTS; client_idx++) {
 | 
						|
      if (!s->clients[client_idx].running) break;
 | 
						|
    }
 | 
						|
 | 
						|
    if (client_idx >= MAX_CLIENTS) {
 | 
						|
      LOG("ignoring visionserver connection, max clients connected");
 | 
						|
      close(fd);
 | 
						|
 | 
						|
      pthread_mutex_unlock(&s->clients_lock);
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    VisionClientState *client = &s->clients[client_idx];
 | 
						|
    client->s = s;
 | 
						|
    client->fd = fd;
 | 
						|
    client->running = true;
 | 
						|
 | 
						|
    err = pthread_create(&client->thread_handle, NULL,
 | 
						|
                         visionserver_client_thread, client);
 | 
						|
    assert(err == 0);
 | 
						|
 | 
						|
    pthread_mutex_unlock(&s->clients_lock);
 | 
						|
  }
 | 
						|
 | 
						|
  for (int i=0; i<MAX_CLIENTS; i++) {
 | 
						|
    pthread_mutex_lock(&s->clients_lock);
 | 
						|
    bool running = s->clients[i].running;
 | 
						|
    pthread_mutex_unlock(&s->clients_lock);
 | 
						|
    if (running) {
 | 
						|
      err = pthread_join(s->clients[i].thread_handle, NULL);
 | 
						|
      assert(err == 0);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  close(sock);
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
void party(cl_device_id device_id, cl_context context) {
 | 
						|
  VisionState state = {};
 | 
						|
  VisionState *s = &state;
 | 
						|
 | 
						|
  cameras_init(&s->cameras, device_id, context);
 | 
						|
  cameras_open(&s->cameras);
 | 
						|
 | 
						|
  std::thread server_thread(visionserver_thread, s);
 | 
						|
 | 
						|
  // priority for cameras
 | 
						|
  int err = set_realtime_priority(53);
 | 
						|
  LOG("setpriority returns %d", err);
 | 
						|
 | 
						|
  cameras_run(&s->cameras);
 | 
						|
 | 
						|
  server_thread.join();
 | 
						|
}
 | 
						|
 | 
						|
#ifdef QCOM
 | 
						|
#include "CL/cl_ext_qcom.h"
 | 
						|
#endif
 | 
						|
 | 
						|
int main(int argc, char *argv[]) {
 | 
						|
  set_realtime_priority(53);
 | 
						|
#if defined(QCOM)
 | 
						|
  set_core_affinity(2);
 | 
						|
#elif defined(QCOM2)
 | 
						|
  set_core_affinity(6);
 | 
						|
#endif
 | 
						|
 | 
						|
  signal(SIGINT, (sighandler_t)set_do_exit);
 | 
						|
  signal(SIGTERM, (sighandler_t)set_do_exit);
 | 
						|
 | 
						|
  cl_device_id device_id = cl_get_device_id(CL_DEVICE_TYPE_DEFAULT);
 | 
						|
 | 
						|
   // TODO: do this for QCOM2 too
 | 
						|
#if defined(QCOM)
 | 
						|
  const cl_context_properties props[] = {CL_CONTEXT_PRIORITY_HINT_QCOM, CL_PRIORITY_HINT_HIGH_QCOM, 0};
 | 
						|
  cl_context context = CL_CHECK_ERR(clCreateContext(props, 1, &device_id, NULL, NULL, &err));
 | 
						|
#else
 | 
						|
  cl_context context = CL_CHECK_ERR(clCreateContext(NULL, 1, &device_id, NULL, NULL, &err));
 | 
						|
#endif
 | 
						|
 | 
						|
  party(device_id, context);
 | 
						|
 | 
						|
  CL_CHECK(clReleaseContext(context));
 | 
						|
}
 | 
						|
 |