openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
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.

146 lines
4.4 KiB

loggerd: switch to v4l encoder try 2 (#24380) * start v4l encoder * v4l encoder starts * start and stop * fill in proper controls * it dequeued a buffer * getting bytes * it made a video * it does make files * getting close * ahh, so that's how dequeue works * qcam works (no remuxing) * remuxing works * we just need to make shutdown and rollover graceful * graceful destruction * switch to polling * should work now * fix pc build * refactors, stop properly * touchups, remove a copy * add v4l encoder to release * inlcude file * move writing to it's own thread * fix minor memory leak * block instead of dropping frames * add counter, fix tests maybe * better debugging and test print * print file path in assert * format string in test * no more oversized qlogs * match qcam * touchups, remove omx encoder * remove omx include files * checked ioctl, better debugging, open by name * unused import * move linux includes to third_party/linux/include * simple encoderd * full packet * encoderd should be complete * lagging print * updates * name dq thread * subset idx * video file writing works * debug * potential bugfix * rotation works * iframe * keep writing support * ci should pass * loggerd, not encoderd * remote encoder code * support remote encoder * cereal to master, add encoderd * header no longer required * put that back there * realtime * lower decoder latency * don't use queue for VisionIpcBufExtra, disable realtime again * assert all written * hmm simpler * only push to to_write if we are writing * assert timestamp is right * use at and remove assert * revert to queue Co-authored-by: Comma Device <device@comma.ai> old-commit-hash: 0baa4c3e2ad9ee6f8daba8267db44c2cd44caa62
3 years ago
#include "selfdrive/loggerd/loggerd.h"
ExitHandler do_exit;
struct EncoderdState {
int max_waiting = 0;
// Sync logic for startup
std::atomic<int> encoders_ready = 0;
std::atomic<uint32_t> start_frame_id = 0;
bool camera_ready[WideRoadCam + 1] = {};
bool camera_synced[WideRoadCam + 1] = {};
};
// Handle initial encoder syncing by waiting for all encoders to reach the same frame id
bool sync_encoders(EncoderdState *s, CameraType cam_type, uint32_t frame_id) {
if (s->camera_synced[cam_type]) return true;
if (s->max_waiting > 1 && s->encoders_ready != s->max_waiting) {
// add a small margin to the start frame id in case one of the encoders already dropped the next frame
update_max_atomic(s->start_frame_id, frame_id + 2);
if (std::exchange(s->camera_ready[cam_type], true) == false) {
++s->encoders_ready;
LOGD("camera %d encoder ready", cam_type);
}
return false;
} else {
if (s->max_waiting == 1) update_max_atomic(s->start_frame_id, frame_id);
bool synced = frame_id >= s->start_frame_id;
s->camera_synced[cam_type] = synced;
if (!synced) LOGD("camera %d waiting for frame %d, cur %d", cam_type, (int)s->start_frame_id, frame_id);
return synced;
}
}
void encoder_thread(EncoderdState *s, const LogCameraInfo &cam_info) {
util::set_thread_name(cam_info.filename);
std::vector<Encoder *> encoders;
VisionIpcClient vipc_client = VisionIpcClient("camerad", cam_info.stream_type, false);
int cur_seg = 0;
while (!do_exit) {
if (!vipc_client.connect(false)) {
util::sleep_for(5);
continue;
}
// init encoders
if (encoders.empty()) {
VisionBuf buf_info = vipc_client.buffers[0];
LOGD("encoder init %dx%d", buf_info.width, buf_info.height);
// main encoder
encoders.push_back(new Encoder(cam_info.filename, cam_info.type, buf_info.width, buf_info.height,
cam_info.fps, cam_info.bitrate, cam_info.is_h265,
buf_info.width, buf_info.height, false));
// qcamera encoder
if (cam_info.has_qcamera) {
encoders.push_back(new Encoder(qcam_info.filename, cam_info.type, buf_info.width, buf_info.height,
qcam_info.fps, qcam_info.bitrate, qcam_info.is_h265,
qcam_info.frame_width, qcam_info.frame_height, false));
}
}
for (int i = 0; i < encoders.size(); ++i) {
encoders[i]->encoder_open(NULL);
}
bool lagging = false;
while (!do_exit) {
VisionIpcBufExtra extra;
VisionBuf* buf = vipc_client.recv(&extra);
if (buf == nullptr) continue;
// detect loop around and drop the frames
if (buf->get_frame_id() != extra.frame_id) {
if (!lagging) {
LOGE("encoder %s lag buffer id: %d extra id: %d", cam_info.filename, buf->get_frame_id(), extra.frame_id);
lagging = true;
}
continue;
}
lagging = false;
if (cam_info.trigger_rotate) {
if (!sync_encoders(s, cam_info.type, extra.frame_id)) {
continue;
}
if (do_exit) break;
}
// encode a frame
for (int i = 0; i < encoders.size(); ++i) {
int out_id = encoders[i]->encode_frame(buf->y, buf->u, buf->v,
buf->width, buf->height, &extra);
if (out_id == -1) {
LOGE("Failed to encode frame. frame_id: %d", extra.frame_id);
}
}
const int frames_per_seg = SEGMENT_LENGTH * MAIN_FPS;
if (cur_seg >= 0 && extra.frame_id >= ((cur_seg + 1) * frames_per_seg) + s->start_frame_id) {
for (auto &e : encoders) {
e->encoder_close();
e->encoder_open(NULL);
}
++cur_seg;
}
}
}
LOG("encoder destroy");
for(auto &e : encoders) {
e->encoder_close();
delete e;
}
}
void encoderd_thread() {
EncoderdState s;
std::vector<std::thread> encoder_threads;
for (const auto &cam : cameras_logged) {
if (cam.enable) {
encoder_threads.push_back(std::thread(encoder_thread, &s, cam));
if (cam.trigger_rotate) s.max_waiting++;
}
}
for (auto &t : encoder_threads) t.join();
}
int main() {
if (Hardware::TICI()) {
int ret;
ret = util::set_realtime_priority(52);
assert(ret == 0);
ret = util::set_core_affinity({7});
assert(ret == 0);
}
encoderd_thread();
return 0;
}