VisionIPC 2.0 (#19641)
* Squashed vipc * Update release files * Remove else * add visionipc to release files * use poller in vipc receive * opencl framework instead of lib on macos * Fix camera webcam * Fix opencl on mac in ui * more webcam fixes * typo in ui sconsfile * Use cur_yuv_buf * visionbuf c++ class * Camera qcom was still using visionbuf_allocate * Turn loggerd back on * fix snapshot * No build needed * update test camerad * no more release callback * make encoder c++ * Revert "no more release callback" This reverts commit e5707b07002fee665d0483d90713154efc2d70d4. * fix exit handlers * No need to check errno * move release callback call * s/VIPCBufExtra/VisionIpcBufExtra/g * use non blocking connect * ui use non blocking connect * Lower condition variable wait time * Snapshot cleanup * bump cereal * bump cerealpull/19698/head
parent
206d072bb4
commit
fb496c692a
46 changed files with 398 additions and 2180 deletions
@ -1 +1 @@ |
||||
Subproject commit 2220a4f10019d0e192f9cdad3bb388790e59f25b |
||||
Subproject commit 266fb9b204cdf4edf5fb8ff4584a4b3eaa35cee2 |
@ -1,93 +0,0 @@ |
||||
#!/usr/bin/env python3 |
||||
import os |
||||
from cffi import FFI |
||||
|
||||
import numpy as np |
||||
|
||||
gf_dir = os.path.dirname(os.path.abspath(__file__)) |
||||
|
||||
ffi = FFI() |
||||
ffi.cdef(""" |
||||
|
||||
typedef enum VisionStreamType { |
||||
VISION_STREAM_RGB_BACK, |
||||
VISION_STREAM_RGB_FRONT, |
||||
VISION_STREAM_YUV, |
||||
VISION_STREAM_YUV_FRONT, |
||||
VISION_STREAM_MAX, |
||||
} VisionStreamType; |
||||
|
||||
typedef struct VisionUIInfo { |
||||
int big_box_x, big_box_y; |
||||
int big_box_width, big_box_height; |
||||
int transformed_width, transformed_height; |
||||
|
||||
int front_box_x, front_box_y; |
||||
int front_box_width, front_box_height; |
||||
} VisionUIInfo; |
||||
|
||||
typedef struct VisionStreamBufs { |
||||
VisionStreamType type; |
||||
|
||||
int width, height, stride; |
||||
size_t buf_len; |
||||
|
||||
union { |
||||
VisionUIInfo ui_info; |
||||
} buf_info; |
||||
} VisionStreamBufs; |
||||
|
||||
typedef struct VIPCBuf { |
||||
int fd; |
||||
size_t len; |
||||
void* addr; |
||||
} VIPCBuf; |
||||
|
||||
typedef struct VIPCBufExtra { |
||||
// only for yuv |
||||
uint32_t frame_id; |
||||
uint64_t timestamp_eof; |
||||
} VIPCBufExtra; |
||||
|
||||
typedef struct VisionStream { |
||||
int ipc_fd; |
||||
int last_idx; |
||||
int last_type; |
||||
int num_bufs; |
||||
VisionStreamBufs bufs_info; |
||||
VIPCBuf *bufs; |
||||
} VisionStream; |
||||
|
||||
int visionstream_init(VisionStream *s, VisionStreamType type, bool tbuffer, VisionStreamBufs *out_bufs_info); |
||||
VIPCBuf* visionstream_get(VisionStream *s, VIPCBufExtra *out_extra); |
||||
void visionstream_destroy(VisionStream *s); |
||||
|
||||
""" |
||||
) |
||||
|
||||
|
||||
class VisionIPCError(Exception): |
||||
pass |
||||
|
||||
|
||||
class VisionIPC(): |
||||
def __init__(self, front=False): |
||||
self.clib = ffi.dlopen(os.path.join(gf_dir, "libvisionipc.so")) |
||||
|
||||
self.s = ffi.new("VisionStream*") |
||||
self.buf_info = ffi.new("VisionStreamBufs*") |
||||
|
||||
err = self.clib.visionstream_init(self.s, self.clib.VISION_STREAM_RGB_FRONT if front else self.clib.VISION_STREAM_RGB_BACK, True, self.buf_info) |
||||
|
||||
if err != 0: |
||||
self.clib.visionstream_destroy(self.s) |
||||
raise VisionIPCError |
||||
|
||||
def __del__(self): |
||||
self.clib.visionstream_destroy(self.s) |
||||
|
||||
def get(self): |
||||
buf = self.clib.visionstream_get(self.s, ffi.NULL) |
||||
pbuf = ffi.buffer(buf.addr, buf.len) |
||||
ret = np.frombuffer(pbuf, dtype=np.uint8).reshape((-1, self.buf_info.stride//3, 3)) |
||||
return ret[:self.buf_info.height, :self.buf_info.width, [2, 1, 0]] |
@ -1,438 +0,0 @@ |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <stdbool.h> |
||||
#include <assert.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
|
||||
#include "common/efd.h" |
||||
|
||||
#include "buffering.h" |
||||
|
||||
void tbuffer_init(TBuffer *tb, int num_bufs, const char* name) { |
||||
assert(num_bufs >= 3); |
||||
|
||||
memset(tb, 0, sizeof(TBuffer)); |
||||
tb->reading = (bool*)calloc(num_bufs, sizeof(bool)); |
||||
assert(tb->reading); |
||||
tb->pending_idx = -1; |
||||
tb->num_bufs = num_bufs; |
||||
tb->name = name; |
||||
|
||||
pthread_mutex_init(&tb->lock, NULL); |
||||
pthread_cond_init(&tb->cv, NULL); |
||||
tb->efd = efd_init(); |
||||
assert(tb->efd >= 0); |
||||
} |
||||
|
||||
void tbuffer_init2(TBuffer *tb, int num_bufs, const char* name, |
||||
void (*release_cb)(void* c, int idx), |
||||
void* cb_cookie) { |
||||
|
||||
tbuffer_init(tb, num_bufs, name); |
||||
|
||||
tb->release_cb = release_cb; |
||||
tb->cb_cookie = cb_cookie; |
||||
} |
||||
|
||||
int tbuffer_efd(TBuffer *tb) { |
||||
return tb->efd; |
||||
} |
||||
|
||||
int tbuffer_select(TBuffer *tb) { |
||||
pthread_mutex_lock(&tb->lock); |
||||
|
||||
int i; |
||||
for (i=0; i<tb->num_bufs; i++) { |
||||
if (!tb->reading[i] && i != tb->pending_idx) { |
||||
break; |
||||
} |
||||
} |
||||
assert(i < tb->num_bufs); |
||||
|
||||
pthread_mutex_unlock(&tb->lock); |
||||
return i; |
||||
} |
||||
|
||||
void tbuffer_dispatch(TBuffer *tb, int idx) { |
||||
pthread_mutex_lock(&tb->lock); |
||||
|
||||
if (tb->pending_idx != -1) { |
||||
//printf("tbuffer (%s) dropped!\n", tb->name ? tb->name : "?");
|
||||
if (tb->release_cb) { |
||||
tb->release_cb(tb->cb_cookie, tb->pending_idx); |
||||
} |
||||
tb->pending_idx = -1; |
||||
} |
||||
|
||||
tb->pending_idx = idx; |
||||
|
||||
efd_write(tb->efd); |
||||
pthread_cond_signal(&tb->cv); |
||||
|
||||
pthread_mutex_unlock(&tb->lock); |
||||
} |
||||
|
||||
int tbuffer_acquire(TBuffer *tb) { |
||||
pthread_mutex_lock(&tb->lock); |
||||
|
||||
if (tb->stopped) { |
||||
pthread_mutex_unlock(&tb->lock); |
||||
return -1; |
||||
} |
||||
|
||||
while (tb->pending_idx == -1) { |
||||
pthread_cond_wait(&tb->cv, &tb->lock); |
||||
|
||||
if (tb->stopped) { |
||||
pthread_mutex_unlock(&tb->lock); |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
efd_clear(tb->efd); |
||||
|
||||
int ret = tb->pending_idx; |
||||
assert(ret < tb->num_bufs); |
||||
|
||||
tb->reading[ret] = true; |
||||
tb->pending_idx = -1; |
||||
|
||||
pthread_mutex_unlock(&tb->lock); |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
static void tbuffer_release_locked(TBuffer *tb, int idx) { |
||||
assert(idx < tb->num_bufs); |
||||
if (!tb->reading[idx]) { |
||||
printf("!! releasing tbuffer we aren't reading %d\n", idx); |
||||
} |
||||
|
||||
if (tb->release_cb) { |
||||
tb->release_cb(tb->cb_cookie, idx); |
||||
} |
||||
|
||||
tb->reading[idx] = false; |
||||
} |
||||
|
||||
void tbuffer_release(TBuffer *tb, int idx) { |
||||
pthread_mutex_lock(&tb->lock); |
||||
tbuffer_release_locked(tb, idx); |
||||
pthread_mutex_unlock(&tb->lock); |
||||
} |
||||
|
||||
void tbuffer_release_all(TBuffer *tb) { |
||||
pthread_mutex_lock(&tb->lock); |
||||
for (int i=0; i<tb->num_bufs; i++) { |
||||
if (tb->reading[i]) { |
||||
tbuffer_release_locked(tb, i); |
||||
} |
||||
} |
||||
pthread_mutex_unlock(&tb->lock); |
||||
} |
||||
|
||||
void tbuffer_stop(TBuffer *tb) { |
||||
pthread_mutex_lock(&tb->lock); |
||||
tb->stopped = true; |
||||
efd_write(tb->efd); |
||||
pthread_cond_signal(&tb->cv); |
||||
pthread_mutex_unlock(&tb->lock); |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void pool_init(Pool *s, int num_bufs) { |
||||
assert(num_bufs > 3); |
||||
|
||||
memset(s, 0, sizeof(*s)); |
||||
s->num_bufs = num_bufs; |
||||
|
||||
s->refcnt = (int*)calloc(num_bufs, sizeof(int)); |
||||
s->ts = (int*)calloc(num_bufs, sizeof(int)); |
||||
|
||||
s->counter = 1; |
||||
|
||||
pthread_mutex_init(&s->lock, NULL); |
||||
} |
||||
|
||||
void pool_init2(Pool *s, int num_bufs, |
||||
void (*release_cb)(void* c, int idx), void* cb_cookie) { |
||||
|
||||
pool_init(s, num_bufs); |
||||
s->cb_cookie = cb_cookie; |
||||
s->release_cb = release_cb; |
||||
|
||||
} |
||||
|
||||
|
||||
void pool_acquire(Pool *s, int idx) { |
||||
pthread_mutex_lock(&s->lock); |
||||
|
||||
assert(idx >= 0 && idx < s->num_bufs); |
||||
|
||||
s->refcnt[idx]++; |
||||
|
||||
pthread_mutex_unlock(&s->lock); |
||||
} |
||||
|
||||
static void pool_release_locked(Pool *s, int idx) { |
||||
// printf("release %d refcnt %d\n", idx, s->refcnt[idx]);
|
||||
|
||||
assert(idx >= 0 && idx < s->num_bufs); |
||||
|
||||
assert(s->refcnt[idx] > 0); |
||||
s->refcnt[idx]--; |
||||
|
||||
// printf("release %d -> %d, %p\n", idx, s->refcnt[idx], s->release_cb);
|
||||
if (s->refcnt[idx] == 0 && s->release_cb) { |
||||
// printf("call %p\b", s->release_cb);
|
||||
s->release_cb(s->cb_cookie, idx); |
||||
} |
||||
} |
||||
|
||||
void pool_release(Pool *s, int idx) { |
||||
pthread_mutex_lock(&s->lock); |
||||
pool_release_locked(s, idx); |
||||
pthread_mutex_unlock(&s->lock); |
||||
} |
||||
|
||||
TBuffer* pool_get_tbuffer(Pool *s) { |
||||
pthread_mutex_lock(&s->lock); |
||||
|
||||
assert(s->num_tbufs < POOL_MAX_TBUFS); |
||||
TBuffer* tbuf = &s->tbufs[s->num_tbufs]; |
||||
s->num_tbufs++; |
||||
tbuffer_init2(tbuf, s->num_bufs, |
||||
"pool", (void (*)(void *, int))pool_release, s); |
||||
|
||||
bool stopped = s->stopped; |
||||
pthread_mutex_unlock(&s->lock); |
||||
|
||||
// Stop the tbuffer so we can return a valid object.
|
||||
// We must stop here because the pool_stop may have already been called,
|
||||
// in which case tbuffer_stop may never be called again.
|
||||
if (stopped) { |
||||
tbuffer_stop(tbuf); |
||||
} |
||||
return tbuf; |
||||
} |
||||
|
||||
PoolQueue* pool_get_queue(Pool *s) { |
||||
pthread_mutex_lock(&s->lock); |
||||
|
||||
int i; |
||||
for (i = 0; i < POOL_MAX_QUEUES; i++) { |
||||
if (!s->queues[i].inited) { |
||||
break; |
||||
} |
||||
} |
||||
assert(i < POOL_MAX_QUEUES); |
||||
|
||||
PoolQueue *c = &s->queues[i]; |
||||
memset(c, 0, sizeof(*c)); |
||||
|
||||
c->pool = s; |
||||
c->inited = true; |
||||
|
||||
c->efd = efd_init(); |
||||
assert(c->efd >= 0); |
||||
|
||||
c->num_bufs = s->num_bufs; |
||||
c->num = c->num_bufs+1; |
||||
c->idx = (int*)malloc(sizeof(int)*c->num); |
||||
memset(c->idx, -1, sizeof(int)*c->num); |
||||
|
||||
pthread_mutex_init(&c->lock, NULL); |
||||
pthread_cond_init(&c->cv, NULL); |
||||
|
||||
pthread_mutex_unlock(&s->lock); |
||||
return c; |
||||
} |
||||
|
||||
void pool_release_queue(PoolQueue *c) { |
||||
Pool *s = c->pool; |
||||
|
||||
pthread_mutex_lock(&s->lock); |
||||
pthread_mutex_lock(&c->lock); |
||||
|
||||
for (int i=0; i<c->num; i++) { |
||||
if (c->idx[i] != -1) { |
||||
pool_release_locked(s, c->idx[i]); |
||||
} |
||||
} |
||||
|
||||
close(c->efd); |
||||
free(c->idx); |
||||
|
||||
c->inited = false; |
||||
|
||||
pthread_mutex_unlock(&c->lock); |
||||
|
||||
pthread_mutex_destroy(&c->lock); |
||||
pthread_cond_destroy(&c->cv); |
||||
|
||||
pthread_mutex_unlock(&s->lock); |
||||
} |
||||
|
||||
int pool_select(Pool *s) { |
||||
pthread_mutex_lock(&s->lock); |
||||
|
||||
int i; |
||||
for (i=0; i<s->num_bufs; i++) { |
||||
if (s->refcnt[i] == 0) { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (i >= s->num_bufs) { |
||||
// overwrite the oldest
|
||||
// still being using in a queue or tbuffer :/
|
||||
|
||||
int min_k = 0; |
||||
int min_ts = s->ts[0]; |
||||
for (int k=1; k<s->num_bufs; k++) { |
||||
if (s->ts[k] < min_ts) { |
||||
min_ts = s->ts[k]; |
||||
min_k = k; |
||||
} |
||||
} |
||||
i = min_k; |
||||
printf("pool is full! evicted %d\n", min_k); |
||||
|
||||
// might be really bad if the user is doing pointery stuff
|
||||
if (s->release_cb) { |
||||
s->release_cb(s->cb_cookie, min_k); |
||||
} |
||||
} |
||||
|
||||
s->refcnt[i]++; |
||||
|
||||
s->ts[i] = s->counter; |
||||
s->counter++; |
||||
|
||||
pthread_mutex_unlock(&s->lock); |
||||
|
||||
return i; |
||||
} |
||||
|
||||
void pool_push(Pool *s, int idx) { |
||||
pthread_mutex_lock(&s->lock); |
||||
|
||||
// printf("push %d head %d tail %d\n", idx, s->head, s->tail);
|
||||
|
||||
assert(idx >= 0 && idx < s->num_bufs); |
||||
|
||||
s->ts[idx] = s->counter; |
||||
s->counter++; |
||||
|
||||
assert(s->refcnt[idx] > 0); |
||||
s->refcnt[idx]--; //push is a implcit release
|
||||
|
||||
int num_tbufs = s->num_tbufs; |
||||
s->refcnt[idx] += num_tbufs; |
||||
|
||||
// dispatch pool queues
|
||||
for (int i=0; i<POOL_MAX_QUEUES; i++) { |
||||
PoolQueue *c = &s->queues[i]; |
||||
if (!c->inited) continue; |
||||
|
||||
pthread_mutex_lock(&c->lock); |
||||
if (((c->head+1) % c->num) == c->tail) { |
||||
// queue is full. skip for now
|
||||
pthread_mutex_unlock(&c->lock); |
||||
continue; |
||||
} |
||||
|
||||
s->refcnt[idx]++; |
||||
|
||||
c->idx[c->head] = idx; |
||||
c->head = (c->head+1) % c->num; |
||||
assert(c->head != c->tail); |
||||
pthread_mutex_unlock(&c->lock); |
||||
|
||||
efd_write(c->efd); |
||||
pthread_cond_signal(&c->cv); |
||||
} |
||||
|
||||
pthread_mutex_unlock(&s->lock); |
||||
|
||||
for (int i=0; i<num_tbufs; i++) { |
||||
tbuffer_dispatch(&s->tbufs[i], idx); |
||||
} |
||||
} |
||||
|
||||
int poolq_pop(PoolQueue *c) { |
||||
pthread_mutex_lock(&c->lock); |
||||
|
||||
if (c->stopped) { |
||||
pthread_mutex_unlock(&c->lock); |
||||
return -1; |
||||
} |
||||
|
||||
while (c->head == c->tail) { |
||||
pthread_cond_wait(&c->cv, &c->lock); |
||||
|
||||
if (c->stopped) { |
||||
pthread_mutex_unlock(&c->lock); |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
// printf("pop head %d tail %d\n", s->head, s->tail);
|
||||
|
||||
assert(c->head != c->tail); |
||||
|
||||
int r = c->idx[c->tail]; |
||||
c->idx[c->tail] = -1; |
||||
c->tail = (c->tail+1) % c->num; |
||||
|
||||
// queue event is level triggered
|
||||
if (c->head == c->tail) { |
||||
efd_clear(c->efd); |
||||
} |
||||
|
||||
// printf("pop %d head %d tail %d\n", r, s->head, s->tail);
|
||||
|
||||
assert(r >= 0 && r < c->num_bufs); |
||||
|
||||
pthread_mutex_unlock(&c->lock); |
||||
|
||||
return r; |
||||
} |
||||
|
||||
int poolq_efd(PoolQueue *c) { |
||||
return c->efd; |
||||
} |
||||
|
||||
void poolq_release(PoolQueue *c, int idx) { |
||||
pool_release(c->pool, idx); |
||||
} |
||||
|
||||
void pool_stop(Pool *s) { |
||||
for (int i=0; i<s->num_tbufs; i++) { |
||||
tbuffer_stop(&s->tbufs[i]); |
||||
} |
||||
|
||||
pthread_mutex_lock(&s->lock); |
||||
s->stopped = true; |
||||
for (int i=0; i<POOL_MAX_QUEUES; i++) { |
||||
PoolQueue *c = &s->queues[i]; |
||||
if (!c->inited) continue; |
||||
|
||||
pthread_mutex_lock(&c->lock); |
||||
c->stopped = true; |
||||
pthread_mutex_unlock(&c->lock); |
||||
efd_write(c->efd); |
||||
pthread_cond_signal(&c->cv); |
||||
} |
||||
pthread_mutex_unlock(&s->lock); |
||||
} |
@ -1,123 +0,0 @@ |
||||
#ifndef BUFFERING_H |
||||
#define BUFFERING_H |
||||
|
||||
#include <stdbool.h> |
||||
#include <pthread.h> |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
// Tripple buffering helper
|
||||
|
||||
typedef struct TBuffer { |
||||
pthread_mutex_t lock; |
||||
pthread_cond_t cv; |
||||
int efd; |
||||
|
||||
bool* reading; |
||||
int pending_idx; |
||||
|
||||
int num_bufs; |
||||
const char* name; |
||||
|
||||
void (*release_cb)(void* c, int idx); |
||||
void *cb_cookie; |
||||
|
||||
bool stopped; |
||||
} TBuffer; |
||||
|
||||
// num_bufs must be at least the number of buffers that can be acquired simultaniously plus two
|
||||
void tbuffer_init(TBuffer *tb, int num_bufs, const char* name); |
||||
|
||||
void tbuffer_init2(TBuffer *tb, int num_bufs, const char* name, |
||||
void (*release_cb)(void* c, int idx), |
||||
void* cb_cookie); |
||||
|
||||
// returns an eventfd that signals if a buffer is ready and tbuffer_acquire shouldn't to block.
|
||||
// useful to polling on multiple tbuffers.
|
||||
int tbuffer_efd(TBuffer *tb); |
||||
|
||||
// Chooses a buffer that's not reading or pending
|
||||
int tbuffer_select(TBuffer *tb); |
||||
|
||||
// Called when the writer is done with their buffer
|
||||
// - Wakes up the reader if it's waiting
|
||||
// - releases the pending buffer if the reader's too slow
|
||||
void tbuffer_dispatch(TBuffer *tb, int idx); |
||||
|
||||
// Called when the reader wants a new buffer, will return -1 when stopped
|
||||
int tbuffer_acquire(TBuffer *tb); |
||||
|
||||
// Called when the reader is done with their buffer
|
||||
void tbuffer_release(TBuffer *tb, int idx); |
||||
|
||||
void tbuffer_release_all(TBuffer *tb); |
||||
|
||||
void tbuffer_stop(TBuffer *tb); |
||||
|
||||
|
||||
|
||||
|
||||
// pool: buffer pool + queue thing...
|
||||
|
||||
#define POOL_MAX_TBUFS 8 |
||||
#define POOL_MAX_QUEUES 8 |
||||
|
||||
typedef struct Pool Pool; |
||||
|
||||
typedef struct PoolQueue { |
||||
pthread_mutex_t lock; |
||||
pthread_cond_t cv; |
||||
Pool* pool; |
||||
bool inited; |
||||
bool stopped; |
||||
int efd; |
||||
int num_bufs; |
||||
int num; |
||||
int head, tail; |
||||
int* idx; |
||||
} PoolQueue; |
||||
|
||||
int poolq_pop(PoolQueue *s); |
||||
int poolq_efd(PoolQueue *s); |
||||
void poolq_release(PoolQueue *c, int idx); |
||||
|
||||
typedef struct Pool { |
||||
pthread_mutex_t lock; |
||||
bool stopped; |
||||
int num_bufs; |
||||
int counter; |
||||
|
||||
int* ts; |
||||
int* refcnt; |
||||
|
||||
void (*release_cb)(void* c, int idx); |
||||
void *cb_cookie; |
||||
|
||||
int num_tbufs; |
||||
TBuffer tbufs[POOL_MAX_TBUFS]; |
||||
PoolQueue queues[POOL_MAX_QUEUES]; |
||||
} Pool; |
||||
|
||||
void pool_init(Pool *s, int num_bufs); |
||||
void pool_init2(Pool *s, int num_bufs, |
||||
void (*release_cb)(void* c, int idx), void* cb_cookie); |
||||
|
||||
TBuffer* pool_get_tbuffer(Pool *s); |
||||
|
||||
PoolQueue* pool_get_queue(Pool *s); |
||||
void pool_release_queue(PoolQueue *q); |
||||
|
||||
int pool_select(Pool *s); |
||||
void pool_push(Pool *s, int idx); |
||||
void pool_acquire(Pool *s, int idx); |
||||
void pool_release(Pool *s, int idx); |
||||
void pool_stop(Pool *s); |
||||
|
||||
|
||||
#ifdef __cplusplus |
||||
} // extern "C"
|
||||
#endif |
||||
|
||||
#endif |
@ -1,56 +0,0 @@ |
||||
#include <stdlib.h> |
||||
#include <assert.h> |
||||
|
||||
#ifdef __linux__ |
||||
#include <sys/eventfd.h> |
||||
#else |
||||
#include <sys/time.h> |
||||
#include <sys/event.h> |
||||
#define EVENT_IDENT 42 |
||||
#endif |
||||
|
||||
#include "efd.h" |
||||
|
||||
|
||||
int efd_init() { |
||||
#ifdef __linux__ |
||||
return eventfd(0, EFD_CLOEXEC); |
||||
#else |
||||
int fd = kqueue(); |
||||
assert(fd >= 0); |
||||
|
||||
struct kevent kev; |
||||
EV_SET(&kev, EVENT_IDENT, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL); |
||||
|
||||
struct timespec timeout = {0, 0}; |
||||
int err = kevent(fd, &kev, 1, NULL, 0, &timeout); |
||||
assert(err != -1); |
||||
|
||||
return fd; |
||||
#endif |
||||
} |
||||
|
||||
void efd_write(int fd) { |
||||
#ifdef __linux__ |
||||
eventfd_write(fd, 1); |
||||
#else |
||||
struct kevent kev; |
||||
EV_SET(&kev, EVENT_IDENT, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); |
||||
|
||||
struct timespec timeout = {0, 0}; |
||||
int err = kevent(fd, &kev, 1, NULL, 0, &timeout); |
||||
assert(err != -1); |
||||
#endif |
||||
} |
||||
|
||||
void efd_clear(int fd) { |
||||
#ifdef __linux__ |
||||
eventfd_t efd_cnt; |
||||
eventfd_read(fd, &efd_cnt); |
||||
#else |
||||
struct kevent kev; |
||||
struct timespec timeout = {0, 0}; |
||||
int nfds = kevent(fd, NULL, 0, &kev, 1, &timeout); |
||||
assert(nfds != -1); |
||||
#endif |
||||
} |
@ -1,17 +0,0 @@ |
||||
#ifndef EFD_H |
||||
#define EFD_H |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
// event fd: a semaphore that can be poll()'d
|
||||
int efd_init(); |
||||
void efd_write(int fd); |
||||
void efd_clear(int fd); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif |
@ -1,125 +0,0 @@ |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <stdbool.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
#include <assert.h> |
||||
#include <errno.h> |
||||
|
||||
#include <sys/mman.h> |
||||
#include <sys/socket.h> |
||||
#include <sys/un.h> |
||||
|
||||
#include "ipc.h" |
||||
|
||||
int ipc_connect(const char* socket_path) { |
||||
int err; |
||||
|
||||
#ifdef __APPLE__ |
||||
int sock = socket(AF_UNIX, SOCK_STREAM, 0); |
||||
#else |
||||
int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); |
||||
#endif |
||||
if (sock < 0) return -1; |
||||
struct sockaddr_un addr = { |
||||
.sun_family = AF_UNIX, |
||||
}; |
||||
snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path); |
||||
err = connect(sock, (struct sockaddr*)&addr, sizeof(addr)); |
||||
if (err != 0) { |
||||
close(sock); |
||||
return -1; |
||||
} |
||||
|
||||
return sock; |
||||
} |
||||
|
||||
int ipc_bind(const char* socket_path) { |
||||
int err; |
||||
|
||||
unlink(socket_path); |
||||
|
||||
#ifdef __APPLE__ |
||||
int sock = socket(AF_UNIX, SOCK_STREAM, 0); |
||||
#else |
||||
int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); |
||||
#endif |
||||
struct sockaddr_un addr = { |
||||
.sun_family = AF_UNIX, |
||||
}; |
||||
snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path); |
||||
err = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); |
||||
assert(err == 0); |
||||
|
||||
err = listen(sock, 3); |
||||
assert(err == 0); |
||||
|
||||
return sock; |
||||
} |
||||
|
||||
|
||||
int ipc_sendrecv_with_fds(bool send, int fd, void *buf, size_t buf_size, int* fds, int num_fds, |
||||
int *out_num_fds) { |
||||
char control_buf[CMSG_SPACE(sizeof(int) * num_fds)]; |
||||
memset(control_buf, 0, CMSG_SPACE(sizeof(int) * num_fds)); |
||||
|
||||
struct iovec iov = { |
||||
.iov_base = buf, |
||||
.iov_len = buf_size, |
||||
}; |
||||
struct msghdr msg = { |
||||
.msg_iov = &iov, |
||||
.msg_iovlen = 1, |
||||
}; |
||||
|
||||
if (num_fds > 0) { |
||||
assert(fds); |
||||
|
||||
msg.msg_control = control_buf; |
||||
msg.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds); |
||||
} |
||||
|
||||
if (send) { |
||||
if (num_fds) { |
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); |
||||
assert(cmsg); |
||||
cmsg->cmsg_level = SOL_SOCKET; |
||||
cmsg->cmsg_type = SCM_RIGHTS; |
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds); |
||||
memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * num_fds); |
||||
// printf("send clen %d -> %d\n", num_fds, cmsg->cmsg_len);
|
||||
} |
||||
return sendmsg(fd, &msg, 0); |
||||
} else { |
||||
int r = recvmsg(fd, &msg, 0); |
||||
if (r < 0) return r; |
||||
|
||||
int recv_fds = 0; |
||||
if (msg.msg_controllen > 0) { |
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); |
||||
assert(cmsg); |
||||
assert(cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS); |
||||
recv_fds = (cmsg->cmsg_len - CMSG_LEN(0)); |
||||
assert(recv_fds > 0 && (recv_fds % sizeof(int)) == 0); |
||||
recv_fds /= sizeof(int); |
||||
// printf("recv clen %d -> %d\n", cmsg->cmsg_len, recv_fds);
|
||||
// assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int) * num_fds));
|
||||
|
||||
assert(fds && recv_fds <= num_fds); |
||||
memcpy(fds, CMSG_DATA(cmsg), sizeof(int) * recv_fds); |
||||
} |
||||
|
||||
if (msg.msg_flags) { |
||||
for (int i=0; i<recv_fds; i++) { |
||||
close(fds[i]); |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
if (fds) { |
||||
assert(out_num_fds); |
||||
*out_num_fds = recv_fds; |
||||
} |
||||
return r; |
||||
} |
||||
} |
@ -1,19 +0,0 @@ |
||||
#ifndef IPC_H |
||||
#define IPC_H |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
int ipc_connect(const char* socket_path); |
||||
int ipc_bind(const char* socket_path); |
||||
int ipc_sendrecv_with_fds(bool send, int fd, void *buf, size_t buf_size, int* fds, int num_fds, |
||||
int *out_num_fds); |
||||
|
||||
#ifdef __cplusplus |
||||
} // extern "C"
|
||||
#endif |
||||
|
||||
#endif |
@ -1,37 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#define CL_USE_DEPRECATED_OPENCL_1_2_APIS |
||||
#ifdef __APPLE__ |
||||
#include <OpenCL/cl.h> |
||||
#else |
||||
#include <CL/cl.h> |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
typedef struct VisionBuf { |
||||
size_t len; |
||||
size_t mmap_len; |
||||
void* addr; |
||||
int handle; |
||||
int fd; |
||||
|
||||
cl_context ctx; |
||||
cl_device_id device_id; |
||||
cl_mem buf_cl; |
||||
cl_command_queue copy_q; |
||||
} VisionBuf; |
||||
|
||||
#define VISIONBUF_SYNC_FROM_DEVICE 0 |
||||
#define VISIONBUF_SYNC_TO_DEVICE 1 |
||||
|
||||
VisionBuf visionbuf_allocate(size_t len); |
||||
VisionBuf visionbuf_allocate_cl(size_t len, cl_device_id device_id, cl_context ctx); |
||||
void visionbuf_sync(const VisionBuf* buf, int dir); |
||||
void visionbuf_free(const VisionBuf* buf); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
@ -1,101 +0,0 @@ |
||||
#include "visionbuf.h" |
||||
|
||||
#include <stdio.h> |
||||
#include <fcntl.h> |
||||
#include <assert.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <sys/mman.h> |
||||
#include <sys/types.h> |
||||
#include "common/clutil.h" |
||||
|
||||
#define CL_USE_DEPRECATED_OPENCL_1_2_APIS |
||||
#ifdef __APPLE__ |
||||
#include <OpenCL/cl.h> |
||||
#else |
||||
#include <CL/cl.h> |
||||
#endif |
||||
|
||||
int offset = 0; |
||||
void *malloc_with_fd(size_t len, int *fd) { |
||||
char full_path[0x100]; |
||||
#ifdef __APPLE__ |
||||
snprintf(full_path, sizeof(full_path)-1, "/tmp/visionbuf_%d_%d", getpid(), offset++); |
||||
#else |
||||
snprintf(full_path, sizeof(full_path)-1, "/dev/shm/visionbuf_%d_%d", getpid(), offset++); |
||||
#endif |
||||
*fd = open(full_path, O_RDWR | O_CREAT, 0777); |
||||
assert(*fd >= 0); |
||||
unlink(full_path); |
||||
ftruncate(*fd, len); |
||||
void *addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0); |
||||
assert(addr != MAP_FAILED); |
||||
return addr; |
||||
} |
||||
|
||||
VisionBuf visionbuf_allocate(size_t len) { |
||||
// const size_t alignment = 4096;
|
||||
// void* addr = aligned_alloc(alignment, alignment * ((len - 1) / alignment + 1));
|
||||
//void* addr = calloc(1, len);
|
||||
|
||||
int fd; |
||||
void *addr = malloc_with_fd(len, &fd); |
||||
|
||||
return (VisionBuf){ |
||||
.len = len, .addr = addr, .handle = 1, .fd = fd, |
||||
}; |
||||
} |
||||
|
||||
VisionBuf visionbuf_allocate_cl(size_t len, cl_device_id device_id, cl_context ctx) { |
||||
#if __OPENCL_VERSION__ >= 200 |
||||
void* host_ptr = |
||||
clSVMAlloc(ctx, CL_MEM_READ_WRITE | CL_MEM_SVM_FINE_GRAIN_BUFFER, len, 0); |
||||
assert(host_ptr); |
||||
#else |
||||
int fd; |
||||
void* host_ptr = malloc_with_fd(len, &fd); |
||||
|
||||
cl_command_queue q = CL_CHECK_ERR(clCreateCommandQueue(ctx, device_id, 0, &err)); |
||||
#endif |
||||
|
||||
cl_mem mem = CL_CHECK_ERR(clCreateBuffer(ctx, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, len, host_ptr, &err)); |
||||
|
||||
return (VisionBuf){ |
||||
.len = len, .addr = host_ptr, .handle = 0, .fd = fd, |
||||
.device_id = device_id, .ctx = ctx, .buf_cl = mem, |
||||
|
||||
#if __OPENCL_VERSION__ < 200 |
||||
.copy_q = q, |
||||
#endif |
||||
|
||||
}; |
||||
} |
||||
|
||||
void visionbuf_sync(const VisionBuf* buf, int dir) { |
||||
if (!buf->buf_cl) return; |
||||
|
||||
#if __OPENCL_VERSION__ < 200 |
||||
if (dir == VISIONBUF_SYNC_FROM_DEVICE) { |
||||
CL_CHECK(clEnqueueReadBuffer(buf->copy_q, buf->buf_cl, CL_FALSE, 0, buf->len, buf->addr, 0, NULL, NULL)); |
||||
} else { |
||||
CL_CHECK(clEnqueueWriteBuffer(buf->copy_q, buf->buf_cl, CL_FALSE, 0, buf->len, buf->addr, 0, NULL, NULL)); |
||||
} |
||||
clFinish(buf->copy_q); |
||||
#endif |
||||
} |
||||
|
||||
void visionbuf_free(const VisionBuf* buf) { |
||||
if (buf->handle) { |
||||
munmap(buf->addr, buf->len); |
||||
close(buf->fd); |
||||
} else { |
||||
CL_CHECK(clReleaseMemObject(buf->buf_cl)); |
||||
#if __OPENCL_VERSION__ >= 200 |
||||
clSVMFree(buf->ctx, buf->addr); |
||||
#else |
||||
CL_CHECK(clReleaseCommandQueue(buf->copy_q)); |
||||
munmap(buf->addr, buf->len); |
||||
close(buf->fd); |
||||
#endif |
||||
} |
||||
} |
@ -1,144 +0,0 @@ |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <assert.h> |
||||
#include <sys/mman.h> |
||||
#include <sys/ioctl.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
#include <linux/ion.h> |
||||
#include <CL/cl_ext.h> |
||||
#include "common/clutil.h" |
||||
#include <msm_ion.h> |
||||
|
||||
#include "visionbuf.h" |
||||
|
||||
|
||||
// just hard-code these for convenience
|
||||
// size_t device_page_size = 0;
|
||||
// clGetDeviceInfo(device_id, CL_DEVICE_PAGE_SIZE_QCOM,
|
||||
// sizeof(device_page_size), &device_page_size,
|
||||
// NULL);
|
||||
|
||||
// size_t padding_cl = 0;
|
||||
// clGetDeviceInfo(device_id, CL_DEVICE_EXT_MEM_PADDING_IN_BYTES_QCOM,
|
||||
// sizeof(padding_cl), &padding_cl,
|
||||
// NULL);
|
||||
#define DEVICE_PAGE_SIZE_CL 4096 |
||||
#define PADDING_CL 0 |
||||
|
||||
static int ion_fd = -1; |
||||
static void ion_init() { |
||||
if (ion_fd == -1) { |
||||
ion_fd = open("/dev/ion", O_RDWR | O_NONBLOCK); |
||||
} |
||||
} |
||||
|
||||
VisionBuf visionbuf_allocate(size_t len) { |
||||
int err; |
||||
|
||||
ion_init(); |
||||
|
||||
struct ion_allocation_data ion_alloc = {0}; |
||||
ion_alloc.len = len + PADDING_CL; |
||||
ion_alloc.align = 4096; |
||||
ion_alloc.heap_id_mask = 1 << ION_IOMMU_HEAP_ID; |
||||
ion_alloc.flags = ION_FLAG_CACHED; |
||||
|
||||
err = ioctl(ion_fd, ION_IOC_ALLOC, &ion_alloc); |
||||
assert(err == 0); |
||||
|
||||
struct ion_fd_data ion_fd_data = {0}; |
||||
ion_fd_data.handle = ion_alloc.handle; |
||||
err = ioctl(ion_fd, ION_IOC_SHARE, &ion_fd_data); |
||||
assert(err == 0); |
||||
|
||||
void *addr = mmap(NULL, ion_alloc.len, |
||||
PROT_READ | PROT_WRITE, |
||||
MAP_SHARED, ion_fd_data.fd, 0); |
||||
assert(addr != MAP_FAILED); |
||||
|
||||
memset(addr, 0, ion_alloc.len); |
||||
|
||||
return (VisionBuf){ |
||||
.len = len, |
||||
.mmap_len = ion_alloc.len, |
||||
.addr = addr, |
||||
.handle = ion_alloc.handle, |
||||
.fd = ion_fd_data.fd, |
||||
}; |
||||
} |
||||
|
||||
VisionBuf visionbuf_allocate_cl(size_t len, cl_device_id device_id, cl_context ctx) { |
||||
VisionBuf buf = visionbuf_allocate(len); |
||||
|
||||
assert(((uintptr_t)buf.addr % DEVICE_PAGE_SIZE_CL) == 0); |
||||
|
||||
cl_mem_ion_host_ptr ion_cl = {0}; |
||||
ion_cl.ext_host_ptr.allocation_type = CL_MEM_ION_HOST_PTR_QCOM; |
||||
ion_cl.ext_host_ptr.host_cache_policy = CL_MEM_HOST_UNCACHED_QCOM; |
||||
ion_cl.ion_filedesc = buf.fd; |
||||
ion_cl.ion_hostptr = buf.addr; |
||||
|
||||
buf.buf_cl = CL_CHECK_ERR(clCreateBuffer(ctx, |
||||
CL_MEM_USE_HOST_PTR | CL_MEM_EXT_HOST_PTR_QCOM, |
||||
buf.len, &ion_cl, &err)); |
||||
return buf; |
||||
} |
||||
|
||||
|
||||
void visionbuf_sync(const VisionBuf* buf, int dir) { |
||||
int err; |
||||
|
||||
struct ion_fd_data fd_data = {0}; |
||||
fd_data.fd = buf->fd; |
||||
err = ioctl(ion_fd, ION_IOC_IMPORT, &fd_data); |
||||
assert(err == 0); |
||||
|
||||
struct ion_flush_data flush_data = {0}; |
||||
flush_data.handle = fd_data.handle; |
||||
flush_data.vaddr = buf->addr; |
||||
flush_data.offset = 0; |
||||
flush_data.length = buf->len; |
||||
|
||||
// ION_IOC_INV_CACHES ~= DMA_FROM_DEVICE
|
||||
// ION_IOC_CLEAN_CACHES ~= DMA_TO_DEVICE
|
||||
// ION_IOC_CLEAN_INV_CACHES ~= DMA_BIDIRECTIONAL
|
||||
|
||||
struct ion_custom_data custom_data = {0}; |
||||
|
||||
switch (dir) { |
||||
case VISIONBUF_SYNC_FROM_DEVICE: |
||||
custom_data.cmd = ION_IOC_INV_CACHES; |
||||
break; |
||||
case VISIONBUF_SYNC_TO_DEVICE: |
||||
custom_data.cmd = ION_IOC_CLEAN_CACHES; |
||||
break; |
||||
default: |
||||
assert(0); |
||||
} |
||||
|
||||
custom_data.arg = (unsigned long)&flush_data; |
||||
err = ioctl(ion_fd, ION_IOC_CUSTOM, &custom_data); |
||||
assert(err == 0); |
||||
|
||||
struct ion_handle_data handle_data = {0}; |
||||
handle_data.handle = fd_data.handle; |
||||
err = ioctl(ion_fd, ION_IOC_FREE, &handle_data); |
||||
assert(err == 0); |
||||
} |
||||
|
||||
void visionbuf_free(const VisionBuf* buf) { |
||||
if (buf->buf_cl) { |
||||
CL_CHECK(clReleaseMemObject(buf->buf_cl)); |
||||
} |
||||
munmap(buf->addr, buf->mmap_len); |
||||
close(buf->fd); |
||||
struct ion_handle_data handle_data = { |
||||
.handle = buf->handle, |
||||
}; |
||||
int ret = ioctl(ion_fd, ION_IOC_FREE, &handle_data); |
||||
assert(ret == 0); |
||||
} |
@ -1,196 +0,0 @@ |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <stdbool.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
#include <assert.h> |
||||
#include <errno.h> |
||||
|
||||
#include <sys/mman.h> |
||||
#include <sys/socket.h> |
||||
#include <sys/un.h> |
||||
|
||||
#include "ipc.h" |
||||
|
||||
#include "visionipc.h" |
||||
|
||||
typedef struct VisionPacketWire { |
||||
int type; |
||||
VisionPacketData d; |
||||
} VisionPacketWire; |
||||
|
||||
int vipc_connect() { |
||||
return ipc_connect(VIPC_SOCKET_PATH); |
||||
} |
||||
|
||||
|
||||
int vipc_recv(int fd, VisionPacket *out_p) { |
||||
VisionPacketWire p = {0}; |
||||
VisionPacket p2 = {0}; |
||||
int ret = ipc_sendrecv_with_fds(false, fd, &p, sizeof(p), (int*)p2.fds, VIPC_MAX_FDS, &p2.num_fds); |
||||
if (ret < 0) { |
||||
printf("vipc_recv err: %s\n", strerror(errno)); |
||||
} else { |
||||
p2.type = p.type; |
||||
p2.d = p.d; |
||||
*out_p = p2; |
||||
} |
||||
//printf("%d = vipc_recv(%d, %d): %d %d %d %zu\n", ret, fd, p2.num_fds, out_p->d.stream_bufs.type, out_p->d.stream_bufs.width, out_p->d.stream_bufs.height, out_p->d.stream_bufs.buf_len);
|
||||
return ret; |
||||
} |
||||
|
||||
int vipc_send(int fd, const VisionPacket *p2) { |
||||
assert(p2->num_fds <= VIPC_MAX_FDS); |
||||
|
||||
VisionPacketWire p = { |
||||
.type = p2->type, |
||||
.d = p2->d, |
||||
}; |
||||
int ret = ipc_sendrecv_with_fds(true, fd, (void*)&p, sizeof(p), (int*)p2->fds, p2->num_fds, NULL); |
||||
//printf("%d = vipc_send(%d, %d): %d %d %d %zu\n", ret, fd, p2->num_fds, p2->d.stream_bufs.type, p2->d.stream_bufs.width, p2->d.stream_bufs.height, p2->d.stream_bufs.buf_len);
|
||||
return ret; |
||||
} |
||||
|
||||
void vipc_bufs_load(VIPCBuf *bufs, const VisionStreamBufs *stream_bufs, |
||||
int num_fds, const int* fds) { |
||||
for (int i=0; i<num_fds; i++) { |
||||
if (bufs[i].addr) { |
||||
munmap(bufs[i].addr, bufs[i].len); |
||||
bufs[i].addr = NULL; |
||||
close(bufs[i].fd); |
||||
} |
||||
bufs[i].fd = fds[i]; |
||||
bufs[i].len = stream_bufs->buf_len; |
||||
bufs[i].addr = mmap(NULL, bufs[i].len, |
||||
PROT_READ | PROT_WRITE, |
||||
MAP_SHARED, bufs[i].fd, 0); |
||||
// printf("b %d %zu -> %p\n", bufs[i].fd, bufs[i].len, bufs[i].addr);
|
||||
assert(bufs[i].addr != MAP_FAILED); |
||||
} |
||||
} |
||||
|
||||
|
||||
int visionstream_init(VisionStream *s, VisionStreamType type, bool tbuffer, VisionStreamBufs *out_bufs_info) { |
||||
int err; |
||||
|
||||
memset(s, 0, sizeof(*s)); |
||||
|
||||
s->last_idx = -1; |
||||
|
||||
s->ipc_fd = vipc_connect(); |
||||
if (s->ipc_fd < 0) return -1; |
||||
|
||||
VisionPacket p = { |
||||
.type = VIPC_STREAM_SUBSCRIBE, |
||||
.d = { .stream_sub = { |
||||
.type = type, |
||||
.tbuffer = tbuffer, |
||||
}, }, |
||||
}; |
||||
err = vipc_send(s->ipc_fd, &p); |
||||
if (err < 0) { |
||||
close(s->ipc_fd); |
||||
s->ipc_fd = -1; |
||||
return -1; |
||||
} |
||||
|
||||
VisionPacket rp; |
||||
err = vipc_recv(s->ipc_fd, &rp); |
||||
if (err <= 0) { |
||||
close(s->ipc_fd); |
||||
s->ipc_fd = -1; |
||||
return -1; |
||||
} |
||||
assert(rp.type == VIPC_STREAM_BUFS); |
||||
assert(rp.d.stream_bufs.type == type); |
||||
|
||||
s->bufs_info = rp.d.stream_bufs; |
||||
|
||||
s->num_bufs = rp.num_fds; |
||||
s->bufs = calloc(s->num_bufs, sizeof(VIPCBuf)); |
||||
assert(s->bufs); |
||||
|
||||
vipc_bufs_load(s->bufs, &rp.d.stream_bufs, s->num_bufs, rp.fds); |
||||
|
||||
if (out_bufs_info) { |
||||
*out_bufs_info = s->bufs_info; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void visionstream_release(VisionStream *s) { |
||||
int err; |
||||
if (s->last_idx >= 0) { |
||||
VisionPacket rep = { |
||||
.type = VIPC_STREAM_RELEASE, |
||||
.d = { .stream_rel = { |
||||
.type = s->last_type, |
||||
.idx = s->last_idx, |
||||
}} |
||||
}; |
||||
err = vipc_send(s->ipc_fd, &rep); |
||||
s->last_idx = -1; |
||||
} |
||||
} |
||||
|
||||
VIPCBuf* visionstream_get(VisionStream *s, VIPCBufExtra *out_extra) { |
||||
int err; |
||||
|
||||
VisionPacket rp; |
||||
err = vipc_recv(s->ipc_fd, &rp); |
||||
if (err <= 0) { |
||||
return NULL; |
||||
} |
||||
assert(rp.type == VIPC_STREAM_ACQUIRE); |
||||
|
||||
if (s->last_idx >= 0) { |
||||
VisionPacket rep = { |
||||
.type = VIPC_STREAM_RELEASE, |
||||
.d = { .stream_rel = { |
||||
.type = s->last_type, |
||||
.idx = s->last_idx, |
||||
}} |
||||
}; |
||||
err = vipc_send(s->ipc_fd, &rep); |
||||
if (err <= 0) { |
||||
return NULL; |
||||
} |
||||
} |
||||
|
||||
s->last_type = rp.d.stream_acq.type; |
||||
s->last_idx = rp.d.stream_acq.idx; |
||||
assert(s->last_idx < s->num_bufs); |
||||
|
||||
if (out_extra) { |
||||
*out_extra = rp.d.stream_acq.extra; |
||||
} |
||||
|
||||
return &s->bufs[s->last_idx]; |
||||
} |
||||
|
||||
void visionstream_destroy(VisionStream *s) { |
||||
int err; |
||||
|
||||
if (s->last_idx >= 0) { |
||||
VisionPacket rep = { |
||||
.type = VIPC_STREAM_RELEASE, |
||||
.d = { .stream_rel = { |
||||
.type = s->last_type, |
||||
.idx = s->last_idx, |
||||
}} |
||||
}; |
||||
err = vipc_send(s->ipc_fd, &rep); |
||||
s->last_idx = -1; |
||||
} |
||||
|
||||
for (int i=0; i<s->num_bufs; i++) { |
||||
if (s->bufs[i].addr) { |
||||
munmap(s->bufs[i].addr, s->bufs[i].len); |
||||
s->bufs[i].addr = NULL; |
||||
close(s->bufs[i].fd); |
||||
} |
||||
} |
||||
if (s->bufs) free(s->bufs); |
||||
if (s->ipc_fd >= 0) close(s->ipc_fd); |
||||
} |
@ -1,120 +0,0 @@ |
||||
#ifndef VISIONIPC_H |
||||
#define VISIONIPC_H |
||||
|
||||
#include <stddef.h> |
||||
#include <stdint.h> |
||||
#include <stdbool.h> |
||||
|
||||
#define VIPC_SOCKET_PATH "/tmp/vision_socket" |
||||
#define VIPC_MAX_FDS 64 |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
typedef enum VisionIPCPacketType { |
||||
VIPC_INVALID = 0, |
||||
VIPC_STREAM_SUBSCRIBE, |
||||
VIPC_STREAM_BUFS, |
||||
VIPC_STREAM_ACQUIRE, |
||||
VIPC_STREAM_RELEASE, |
||||
} VisionIPCPacketType; |
||||
|
||||
typedef enum VisionStreamType { |
||||
VISION_STREAM_RGB_BACK, |
||||
VISION_STREAM_RGB_FRONT, |
||||
VISION_STREAM_RGB_WIDE, |
||||
VISION_STREAM_YUV, |
||||
VISION_STREAM_YUV_FRONT, |
||||
VISION_STREAM_YUV_WIDE, |
||||
VISION_STREAM_MAX, |
||||
} VisionStreamType; |
||||
|
||||
typedef struct VisionUIInfo { |
||||
int big_box_x, big_box_y; |
||||
int big_box_width, big_box_height; |
||||
int transformed_width, transformed_height; |
||||
|
||||
int front_box_x, front_box_y; |
||||
int front_box_width, front_box_height; |
||||
|
||||
int wide_box_x, wide_box_y; |
||||
int wide_box_width, wide_box_height; |
||||
|
||||
} VisionUIInfo; |
||||
|
||||
typedef struct VisionStreamBufs { |
||||
VisionStreamType type; |
||||
|
||||
int width, height, stride; |
||||
size_t buf_len; |
||||
|
||||
union { |
||||
VisionUIInfo ui_info; |
||||
} buf_info; |
||||
} VisionStreamBufs; |
||||
|
||||
typedef struct VIPCBufExtra { |
||||
// only for yuv
|
||||
uint32_t frame_id; |
||||
uint64_t timestamp_sof; |
||||
uint64_t timestamp_eof; |
||||
} VIPCBufExtra; |
||||
|
||||
typedef union VisionPacketData { |
||||
struct { |
||||
VisionStreamType type; |
||||
bool tbuffer; |
||||
} stream_sub; |
||||
VisionStreamBufs stream_bufs; |
||||
struct { |
||||
VisionStreamType type; |
||||
int idx; |
||||
VIPCBufExtra extra; |
||||
} stream_acq; |
||||
struct { |
||||
VisionStreamType type; |
||||
int idx; |
||||
} stream_rel; |
||||
} VisionPacketData; |
||||
|
||||
typedef struct VisionPacket { |
||||
int type; |
||||
VisionPacketData d; |
||||
int num_fds; |
||||
int fds[VIPC_MAX_FDS]; |
||||
} VisionPacket; |
||||
|
||||
int vipc_connect(void); |
||||
int vipc_recv(int fd, VisionPacket *out_p); |
||||
int vipc_send(int fd, const VisionPacket *p); |
||||
|
||||
typedef struct VIPCBuf { |
||||
int fd; |
||||
size_t len; |
||||
void* addr; |
||||
} VIPCBuf; |
||||
void vipc_bufs_load(VIPCBuf *bufs, const VisionStreamBufs *stream_bufs, |
||||
int num_fds, const int* fds); |
||||
|
||||
|
||||
|
||||
typedef struct VisionStream { |
||||
int ipc_fd; |
||||
int last_idx; |
||||
int last_type; |
||||
int num_bufs; |
||||
VisionStreamBufs bufs_info; |
||||
VIPCBuf *bufs; |
||||
} VisionStream; |
||||
|
||||
int visionstream_init(VisionStream *s, VisionStreamType type, bool tbuffer, VisionStreamBufs *out_bufs_info); |
||||
void visionstream_release(VisionStream *s); |
||||
VIPCBuf* visionstream_get(VisionStream *s, VIPCBufExtra *out_extra); |
||||
void visionstream_destroy(VisionStream *s); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif |
Loading…
Reference in new issue