|
|
|
@ -4,12 +4,10 @@ |
|
|
|
|
#include <cassert> |
|
|
|
|
#include <unistd.h> |
|
|
|
|
#include <errno.h> |
|
|
|
|
#include <poll.h> |
|
|
|
|
#include <string.h> |
|
|
|
|
#include <inttypes.h> |
|
|
|
|
#include <libyuv.h> |
|
|
|
|
#include <sys/resource.h> |
|
|
|
|
#include <pthread.h> |
|
|
|
|
#include <sys/resource.h> |
|
|
|
|
|
|
|
|
|
#include <string> |
|
|
|
|
#include <iostream> |
|
|
|
@ -46,15 +44,14 @@ |
|
|
|
|
#include "encoder.h" |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#define MAIN_BITRATE 5000000 |
|
|
|
|
#define QCAM_BITRATE 128000 |
|
|
|
|
#define MAIN_FPS 20 |
|
|
|
|
constexpr int MAIN_BITRATE = 5000000; |
|
|
|
|
constexpr int MAIN_FPS = 20; |
|
|
|
|
#ifndef QCOM2 |
|
|
|
|
#define MAX_CAM_IDX LOG_CAMERA_ID_DCAMERA |
|
|
|
|
#define DCAM_BITRATE 2500000 |
|
|
|
|
constexpr int MAX_CAM_IDX = LOG_CAMERA_ID_DCAMERA; |
|
|
|
|
constexpr int DCAM_BITRATE = 2500000; |
|
|
|
|
#else |
|
|
|
|
#define MAX_CAM_IDX LOG_CAMERA_ID_ECAMERA |
|
|
|
|
#define DCAM_BITRATE MAIN_BITRATE |
|
|
|
|
constexpr int MAX_CAM_IDX = LOG_CAMERA_ID_ECAMERA; |
|
|
|
|
constexpr int DCAM_BITRATE = MAIN_BITRATE; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#define NO_CAMERA_PATIENCE 500 // fall back to time-based rotation if all cameras are dead
|
|
|
|
@ -93,7 +90,7 @@ LogCameraInfo cameras_logged[LOG_CAMERA_ID_MAX] = { |
|
|
|
|
[LOG_CAMERA_ID_QCAMERA] = { |
|
|
|
|
.filename = "qcamera.ts", |
|
|
|
|
.fps = MAIN_FPS, |
|
|
|
|
.bitrate = QCAM_BITRATE, |
|
|
|
|
.bitrate = 128000, |
|
|
|
|
.is_h265 = false, |
|
|
|
|
.downscale = true, |
|
|
|
|
#ifndef QCOM2 |
|
|
|
@ -105,12 +102,12 @@ LogCameraInfo cameras_logged[LOG_CAMERA_ID_MAX] = { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace { |
|
|
|
|
|
|
|
|
|
constexpr int SEGMENT_LENGTH = 60; |
|
|
|
|
const char* LOG_ROOT = "/data/media/0/realdata"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace { |
|
|
|
|
|
|
|
|
|
double randrange(double a, double b) __attribute__((unused)); |
|
|
|
|
double randrange(double a, double b) { |
|
|
|
|
static std::mt19937 gen(millis_since_boot()); |
|
|
|
@ -144,7 +141,9 @@ public: |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void cancelWait() { cv.notify_one(); } |
|
|
|
|
void cancelWait() { |
|
|
|
|
cv.notify_one(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void setStreamFrameId(uint32_t frame_id) { |
|
|
|
|
fid_lock.lock(); |
|
|
|
@ -161,11 +160,12 @@ public: |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void rotate() { |
|
|
|
|
if (!enabled) { return; } |
|
|
|
|
if (enabled) { |
|
|
|
|
std::unique_lock<std::mutex> lk(fid_lock); |
|
|
|
|
should_rotate = true; |
|
|
|
|
last_rotate_frame_id = stream_frame_id; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void finish_rotate() { |
|
|
|
|
std::unique_lock<std::mutex> lk(fid_lock); |
|
|
|
@ -183,11 +183,12 @@ struct LoggerdState { |
|
|
|
|
char segment_path[4096]; |
|
|
|
|
int rotate_segment; |
|
|
|
|
pthread_mutex_t rotate_lock; |
|
|
|
|
|
|
|
|
|
// video encders
|
|
|
|
|
int num_encoder; |
|
|
|
|
std::atomic<int> rotate_seq_id; |
|
|
|
|
std::atomic<int> should_close; |
|
|
|
|
std::atomic<int> finish_close; |
|
|
|
|
|
|
|
|
|
RotateState rotate_state[LOG_CAMERA_ID_MAX-1]; |
|
|
|
|
}; |
|
|
|
|
LoggerdState s; |
|
|
|
@ -204,13 +205,12 @@ void encoder_thread(int cam_idx) { |
|
|
|
|
|
|
|
|
|
std::vector<EncoderState*> encoders; |
|
|
|
|
|
|
|
|
|
int encoder_segment = -1; |
|
|
|
|
int cnt = 0; |
|
|
|
|
pthread_mutex_lock(&s.rotate_lock); |
|
|
|
|
int my_idx = s.num_encoder; |
|
|
|
|
s.num_encoder += 1; |
|
|
|
|
pthread_mutex_unlock(&s.rotate_lock); |
|
|
|
|
|
|
|
|
|
int cnt = 0; |
|
|
|
|
LoggerHandle *lh = NULL; |
|
|
|
|
|
|
|
|
|
while (!do_exit) { |
|
|
|
@ -222,6 +222,7 @@ void encoder_thread(int cam_idx) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// init encoders
|
|
|
|
|
if (encoders.empty()) { |
|
|
|
|
LOGD("encoder init %dx%d", buf_info.width, buf_info.height); |
|
|
|
|
|
|
|
|
@ -252,8 +253,8 @@ void encoder_thread(int cam_idx) { |
|
|
|
|
//double msdiff = (double) diff / 1000000.0;
|
|
|
|
|
// printf("logger latency to tsEof: %f\n", msdiff);
|
|
|
|
|
|
|
|
|
|
{ // all the rotation stuff
|
|
|
|
|
|
|
|
|
|
// all the rotation stuff
|
|
|
|
|
{ |
|
|
|
|
pthread_mutex_lock(&s.rotate_lock); |
|
|
|
|
pthread_mutex_unlock(&s.rotate_lock); |
|
|
|
|
|
|
|
|
@ -269,7 +270,8 @@ void encoder_thread(int cam_idx) { |
|
|
|
|
rotate_state.initialized = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
while (s.rotate_seq_id != my_idx && !do_exit) { usleep(1000); } |
|
|
|
|
// poll for our turn
|
|
|
|
|
while (s.rotate_seq_id != my_idx && !do_exit) util::sleep_for(10); |
|
|
|
|
|
|
|
|
|
LOGW("camera %d rotate encoder to %s.", cam_idx, s.segment_path); |
|
|
|
|
for (auto &e : encoders) { |
|
|
|
@ -277,7 +279,6 @@ void encoder_thread(int cam_idx) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
s.rotate_seq_id = (my_idx + 1) % s.num_encoder; |
|
|
|
|
encoder_segment = s.rotate_segment; |
|
|
|
|
if (lh) { |
|
|
|
|
lh_close(lh); |
|
|
|
|
} |
|
|
|
@ -287,7 +288,7 @@ void encoder_thread(int cam_idx) { |
|
|
|
|
s.should_close += 1; |
|
|
|
|
pthread_mutex_unlock(&s.rotate_lock); |
|
|
|
|
|
|
|
|
|
while(s.should_close > 0 && s.should_close < s.num_encoder && !do_exit) { usleep(1000); } |
|
|
|
|
while(s.should_close > 0 && s.should_close < s.num_encoder && !do_exit) util::sleep_for(10); |
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&s.rotate_lock); |
|
|
|
|
s.should_close = s.should_close == s.num_encoder ? 1 - s.num_encoder : s.should_close + 1; |
|
|
|
@ -302,7 +303,8 @@ void encoder_thread(int cam_idx) { |
|
|
|
|
s.finish_close += 1; |
|
|
|
|
pthread_mutex_unlock(&s.rotate_lock); |
|
|
|
|
|
|
|
|
|
while(s.finish_close > 0 && s.finish_close < s.num_encoder && !do_exit) { usleep(1000); } |
|
|
|
|
// wait for all to finish
|
|
|
|
|
while(s.finish_close > 0 && s.finish_close < s.num_encoder && !do_exit) util::sleep_for(10); |
|
|
|
|
s.finish_close = 0; |
|
|
|
|
|
|
|
|
|
rotate_state.finish_rotate(); |
|
|
|
@ -384,9 +386,9 @@ kj::Array<capnp::word> gen_init_data() { |
|
|
|
|
MessageBuilder msg; |
|
|
|
|
auto init = msg.initEvent().initInitData(); |
|
|
|
|
|
|
|
|
|
if (file_exists("/EON")) |
|
|
|
|
if (file_exists("/EON")) { |
|
|
|
|
init.setDeviceType(cereal::InitData::DeviceType::NEO); |
|
|
|
|
else if (file_exists("/TICI")) { |
|
|
|
|
} else if (file_exists("/TICI")) { |
|
|
|
|
init.setDeviceType(cereal::InitData::DeviceType::TICI); |
|
|
|
|
} else { |
|
|
|
|
init.setDeviceType(cereal::InitData::DeviceType::PC); |
|
|
|
@ -426,31 +428,15 @@ kj::Array<capnp::word> gen_init_data() { |
|
|
|
|
if (dongle_id) { |
|
|
|
|
init.setDongleId(std::string(dongle_id)); |
|
|
|
|
} |
|
|
|
|
init.setDirty(!getenv("CLEAN")); |
|
|
|
|
|
|
|
|
|
const char* clean = getenv("CLEAN"); |
|
|
|
|
if (!clean) { |
|
|
|
|
init.setDirty(true); |
|
|
|
|
} |
|
|
|
|
// log params
|
|
|
|
|
Params params = Params(); |
|
|
|
|
|
|
|
|
|
std::vector<char> git_commit = params.read_db_bytes("GitCommit"); |
|
|
|
|
if (git_commit.size() > 0) { |
|
|
|
|
init.setGitCommit(capnp::Text::Reader(git_commit.data(), git_commit.size())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::vector<char> git_branch = params.read_db_bytes("GitBranch"); |
|
|
|
|
if (git_branch.size() > 0) { |
|
|
|
|
init.setGitBranch(capnp::Text::Reader(git_branch.data(), git_branch.size())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::vector<char> git_remote = params.read_db_bytes("GitRemote"); |
|
|
|
|
if (git_remote.size() > 0) { |
|
|
|
|
init.setGitRemote(capnp::Text::Reader(git_remote.data(), git_remote.size())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
init.setGitCommit(params.get("GitCommit")); |
|
|
|
|
init.setGitBranch(params.get("GitBranch")); |
|
|
|
|
init.setGitRemote(params.get("GitRemote")); |
|
|
|
|
init.setPassive(params.read_db_bool("Passive")); |
|
|
|
|
{ |
|
|
|
|
// log params
|
|
|
|
|
std::map<std::string, std::string> params_map; |
|
|
|
|
params.read_db_all(¶ms_map); |
|
|
|
|
auto lparams = init.initParams().initEntries(params_map.size()); |
|
|
|
@ -513,11 +499,8 @@ static void bootlog() { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int main(int argc, char** argv) { |
|
|
|
|
int err; |
|
|
|
|
|
|
|
|
|
#ifdef QCOM |
|
|
|
|
setpriority(PRIO_PROCESS, 0, -12); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
if (argc > 1 && strcmp(argv[1], "--bootlog") == 0) { |
|
|
|
|
bootlog(); |
|
|
|
@ -528,6 +511,7 @@ int main(int argc, char** argv) { |
|
|
|
|
if (getenv("LOGGERD_TEST")) { |
|
|
|
|
segment_length = atoi(getenv("LOGGERD_SEGMENT_LENGTH")); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool record_front = true; |
|
|
|
|
#ifndef QCOM2 |
|
|
|
|
record_front = Params().read_db_bool("RecordFront"); |
|
|
|
@ -576,6 +560,7 @@ int main(int argc, char** argv) { |
|
|
|
|
s.num_encoder = 0; |
|
|
|
|
pthread_mutex_init(&s.rotate_lock, NULL); |
|
|
|
|
|
|
|
|
|
// TODO: create these threads dynamically on frame packet presence
|
|
|
|
|
std::vector<std::thread> encoder_threads; |
|
|
|
|
#ifndef DISABLE_ENCODER |
|
|
|
|
encoder_threads.push_back(std::thread(encoder_thread, LOG_CAMERA_ID_FCAMERA)); |
|
|
|
@ -600,7 +585,11 @@ int main(int argc, char** argv) { |
|
|
|
|
double last_rotate_tms = millis_since_boot(); |
|
|
|
|
double last_camera_seen_tms = millis_since_boot(); |
|
|
|
|
while (!do_exit) { |
|
|
|
|
// TODO: fix msgs from the first poll getting dropped
|
|
|
|
|
// poll for new messages on all sockets
|
|
|
|
|
for (auto sock : poller->poll(1000)) { |
|
|
|
|
|
|
|
|
|
// drain socket
|
|
|
|
|
Message * last_msg = nullptr; |
|
|
|
|
while (!do_exit) { |
|
|
|
|
Message * msg = sock->receive(true); |
|
|
|
@ -612,11 +601,10 @@ int main(int argc, char** argv) { |
|
|
|
|
|
|
|
|
|
QlogState& qs = qlog_states[sock]; |
|
|
|
|
logger_log(&s.logger, (uint8_t*)msg->getData(), msg->getSize(), qs.counter == 0); |
|
|
|
|
|
|
|
|
|
if (qs.counter != -1) { |
|
|
|
|
//printf("%p: %d/%d\n", socks[i], qlog_counter[socks[i]], qlog_freqs[socks[i]]);
|
|
|
|
|
qs.counter = (qs.counter + 1) % qs.freq; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bytes_count += msg->getSize(); |
|
|
|
|
msg_count++; |
|
|
|
|
} |
|
|
|
@ -649,51 +637,51 @@ int main(int argc, char** argv) { |
|
|
|
|
} |
|
|
|
|
last_camera_seen_tms = millis_since_boot(); |
|
|
|
|
} |
|
|
|
|
delete last_msg; |
|
|
|
|
} |
|
|
|
|
delete last_msg; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
double ts = seconds_since_boot(); |
|
|
|
|
double tms = millis_since_boot(); |
|
|
|
|
|
|
|
|
|
bool new_segment = false; |
|
|
|
|
|
|
|
|
|
bool new_segment = s.logger.part == -1; |
|
|
|
|
if (s.logger.part > -1) { |
|
|
|
|
new_segment = true; |
|
|
|
|
double tms = millis_since_boot(); |
|
|
|
|
if (tms - last_camera_seen_tms <= NO_CAMERA_PATIENCE && s.num_encoder > 0) { |
|
|
|
|
for (int cid=0;cid<=MAX_CAM_IDX;cid++) { |
|
|
|
|
new_segment = true; |
|
|
|
|
for (auto &r : s.rotate_state) { |
|
|
|
|
// this *should* be redundant on tici since all camera frames are synced
|
|
|
|
|
new_segment &= (((s.rotate_state[cid].stream_frame_id >= s.rotate_state[cid].last_rotate_frame_id + segment_length * MAIN_FPS) && |
|
|
|
|
(!s.rotate_state[cid].should_rotate) && (s.rotate_state[cid].initialized)) || |
|
|
|
|
(!s.rotate_state[cid].enabled)); |
|
|
|
|
new_segment &= (((r.stream_frame_id >= r.last_rotate_frame_id + segment_length * MAIN_FPS) && |
|
|
|
|
(!r.should_rotate) && (r.initialized)) || |
|
|
|
|
(!r.enabled)); |
|
|
|
|
#ifndef QCOM2 |
|
|
|
|
break; // only look at fcamera frame id if not QCOM2
|
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
new_segment &= tms - last_rotate_tms > segment_length * 1000; |
|
|
|
|
if (new_segment) { LOGW("no camera packet seen. auto rotated"); } |
|
|
|
|
} |
|
|
|
|
} else if (s.logger.part == -1) { |
|
|
|
|
// always starts first segment immediately
|
|
|
|
|
if (tms - last_rotate_tms > segment_length * 1000) { |
|
|
|
|
new_segment = true; |
|
|
|
|
LOGW("no camera packet seen. auto rotated"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// rotate to new segment
|
|
|
|
|
if (new_segment) { |
|
|
|
|
pthread_mutex_lock(&s.rotate_lock); |
|
|
|
|
last_rotate_tms = millis_since_boot(); |
|
|
|
|
|
|
|
|
|
err = logger_next(&s.logger, LOG_ROOT, s.segment_path, sizeof(s.segment_path), &s.rotate_segment); |
|
|
|
|
int err = logger_next(&s.logger, LOG_ROOT, s.segment_path, sizeof(s.segment_path), &s.rotate_segment); |
|
|
|
|
assert(err == 0); |
|
|
|
|
if (s.logger.part == 0) { LOGW("logging to %s", s.segment_path); } |
|
|
|
|
if (s.logger.part == 0) { |
|
|
|
|
LOGW("logging to %s", s.segment_path); |
|
|
|
|
} |
|
|
|
|
LOGW("rotated to %s", s.segment_path); |
|
|
|
|
|
|
|
|
|
// rotate the encoders
|
|
|
|
|
for (int cid=0;cid<=MAX_CAM_IDX;cid++) { s.rotate_state[cid].rotate(); } |
|
|
|
|
// rotate encoders
|
|
|
|
|
for (auto &r : s.rotate_state) r.rotate(); |
|
|
|
|
pthread_mutex_unlock(&s.rotate_lock); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ((msg_count % 1000) == 0) { |
|
|
|
|
double ts = seconds_since_boot(); |
|
|
|
|
LOGD("%lu messages, %.2f msg/sec, %.2f KB/sec", msg_count, msg_count*1.0/(ts-start_ts), bytes_count*0.001/(ts-start_ts)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|