mirror of
https://github.com/infiniteCable2/openpilot.git
synced 2026-07-25 19:32:03 +08:00
encoderd: more efficient compression for low res frames (#35924)
* shein says inline * Update system/loggerd/loggerd.h Co-authored-by: Shane Smiskol <shane@smiskol.com> * Revert "Update system/loggerd/loggerd.h" This reverts commit 3602523cefdeb2a46d77946f7f2cc7fc21bd5a4f. * Revert "shein says inline" This reverts commit d3c079e137c5d98068501df636975c5fbf8810ee. * EncoderSettings * getter * update test_encoder * def --------- Co-authored-by: Comma Device <device@comma.ai> Co-authored-by: Shane Smiskol <shane@smiskol.com>
This commit is contained in:
@@ -21,7 +21,7 @@ void VideoEncoder::publisher_publish(int segment_num, uint32_t idx, VisionIpcBuf
|
||||
edata.setFrameId(extra.frame_id);
|
||||
edata.setTimestampSof(extra.timestamp_sof);
|
||||
edata.setTimestampEof(extra.timestamp_eof);
|
||||
edata.setType(encoder_info.settings.encode_type);
|
||||
edata.setType(encoder_info.get_settings(in_width).encode_type);
|
||||
edata.setEncodeId(cnt++);
|
||||
edata.setSegmentNum(segment_num);
|
||||
edata.setSegmentId(idx);
|
||||
|
||||
@@ -46,7 +46,7 @@ FfmpegEncoder::~FfmpegEncoder() {
|
||||
}
|
||||
|
||||
void FfmpegEncoder::encoder_open() {
|
||||
auto codec_id = encoder_info.settings.encode_type == cereal::EncodeIndex::Type::QCAMERA_H264
|
||||
auto codec_id = encoder_info.get_settings(in_width).encode_type == cereal::EncodeIndex::Type::QCAMERA_H264
|
||||
? AV_CODEC_ID_H264
|
||||
: AV_CODEC_ID_FFVHUFF;
|
||||
const AVCodec *codec = avcodec_find_encoder(codec_id);
|
||||
|
||||
@@ -155,7 +155,8 @@ V4LEncoder::V4LEncoder(const EncoderInfo &encoder_info, int in_width, int in_hei
|
||||
assert(strcmp((const char *)cap.driver, "msm_vidc_driver") == 0);
|
||||
assert(strcmp((const char *)cap.card, "msm_vidc_venc") == 0);
|
||||
|
||||
bool is_h265 = encoder_info.settings.encode_type == cereal::EncodeIndex::Type::FULL_H_E_V_C;
|
||||
EncoderSettings encoder_settings = encoder_info.get_settings(in_width);
|
||||
bool is_h265 = encoder_settings.encode_type == cereal::EncodeIndex::Type::FULL_H_E_V_C;
|
||||
|
||||
struct v4l2_format fmt_out = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
|
||||
@@ -207,9 +208,9 @@ V4LEncoder::V4LEncoder(const EncoderInfo &encoder_info, int in_width, int in_hei
|
||||
// shared ctrls
|
||||
{
|
||||
struct v4l2_control ctrls[] = {
|
||||
{ .id = V4L2_CID_MPEG_VIDEO_BITRATE, .value = encoder_info.settings.bitrate},
|
||||
{ .id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES, .value = encoder_info.settings.gop_size - encoder_info.settings.b_frames - 1},
|
||||
{ .id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES, .value = encoder_info.settings.b_frames},
|
||||
{ .id = V4L2_CID_MPEG_VIDEO_BITRATE, .value = encoder_settings.bitrate},
|
||||
{ .id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES, .value = encoder_settings.gop_size - encoder_settings.b_frames - 1},
|
||||
{ .id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES, .value = encoder_settings.b_frames},
|
||||
{ .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE, .value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE},
|
||||
{ .id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL, .value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR},
|
||||
{ .id = V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY, .value = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE},
|
||||
|
||||
+14
-15
@@ -33,13 +33,12 @@ struct EncoderSettings {
|
||||
int gop_size;
|
||||
int b_frames = 0; // we don't use b frames
|
||||
|
||||
static EncoderSettings MainEncoderSettings() {
|
||||
//static EncoderSettings MainEncoderSettings(int in_width) {
|
||||
//if (in_width <= 1344) {
|
||||
// return EncoderSettings{.bitrate = 5'000'000, .gop_size = 20};
|
||||
//} else {
|
||||
return EncoderSettings{.encode_type = MAIN_ENCODE_TYPE, .bitrate = 10'000'000, .gop_size = 30};
|
||||
//}
|
||||
static EncoderSettings MainEncoderSettings(int in_width) {
|
||||
if (in_width <= 1344) {
|
||||
return EncoderSettings{.encode_type = MAIN_ENCODE_TYPE, .bitrate = 5'000'000, .gop_size = 20};
|
||||
} else {
|
||||
return EncoderSettings{.encode_type = MAIN_ENCODE_TYPE, .bitrate = 10'000'000, .gop_size = 30};
|
||||
}
|
||||
}
|
||||
|
||||
static EncoderSettings QcamEncoderSettings() {
|
||||
@@ -61,7 +60,7 @@ public:
|
||||
int frame_width = -1;
|
||||
int frame_height = -1;
|
||||
int fps = MAIN_FPS;
|
||||
EncoderSettings settings;
|
||||
std::function<EncoderSettings(int)> get_settings;
|
||||
|
||||
::cereal::EncodeData::Reader (cereal::Event::Reader::*get_encode_data_func)() const;
|
||||
void (cereal::Event::Builder::*set_encode_idx_func)(::cereal::EncodeIndex::Reader);
|
||||
@@ -80,14 +79,14 @@ const EncoderInfo main_road_encoder_info = {
|
||||
.publish_name = "roadEncodeData",
|
||||
.thumbnail_name = "thumbnail",
|
||||
.filename = "fcamera.hevc",
|
||||
.settings = EncoderSettings::MainEncoderSettings(),
|
||||
.get_settings = [](int in_width){return EncoderSettings::MainEncoderSettings(in_width);},
|
||||
INIT_ENCODE_FUNCTIONS(RoadEncode),
|
||||
};
|
||||
|
||||
const EncoderInfo main_wide_road_encoder_info = {
|
||||
.publish_name = "wideRoadEncodeData",
|
||||
.filename = "ecamera.hevc",
|
||||
.settings = EncoderSettings::MainEncoderSettings(),
|
||||
.get_settings = [](int in_width){return EncoderSettings::MainEncoderSettings(in_width);},
|
||||
INIT_ENCODE_FUNCTIONS(WideRoadEncode),
|
||||
};
|
||||
|
||||
@@ -95,7 +94,7 @@ const EncoderInfo main_driver_encoder_info = {
|
||||
.publish_name = "driverEncodeData",
|
||||
.filename = "dcamera.hevc",
|
||||
.record = Params().getBool("RecordFront"),
|
||||
.settings = EncoderSettings::MainEncoderSettings(),
|
||||
.get_settings = [](int in_width){return EncoderSettings::MainEncoderSettings(in_width);},
|
||||
INIT_ENCODE_FUNCTIONS(DriverEncode),
|
||||
};
|
||||
|
||||
@@ -103,28 +102,28 @@ const EncoderInfo stream_road_encoder_info = {
|
||||
.publish_name = "livestreamRoadEncodeData",
|
||||
//.thumbnail_name = "thumbnail",
|
||||
.record = false,
|
||||
.settings = EncoderSettings::StreamEncoderSettings(),
|
||||
.get_settings = [](int){return EncoderSettings::StreamEncoderSettings();},
|
||||
INIT_ENCODE_FUNCTIONS(LivestreamRoadEncode),
|
||||
};
|
||||
|
||||
const EncoderInfo stream_wide_road_encoder_info = {
|
||||
.publish_name = "livestreamWideRoadEncodeData",
|
||||
.record = false,
|
||||
.settings = EncoderSettings::StreamEncoderSettings(),
|
||||
.get_settings = [](int){return EncoderSettings::StreamEncoderSettings();},
|
||||
INIT_ENCODE_FUNCTIONS(LivestreamWideRoadEncode),
|
||||
};
|
||||
|
||||
const EncoderInfo stream_driver_encoder_info = {
|
||||
.publish_name = "livestreamDriverEncodeData",
|
||||
.record = false,
|
||||
.settings = EncoderSettings::StreamEncoderSettings(),
|
||||
.get_settings = [](int){return EncoderSettings::StreamEncoderSettings();},
|
||||
INIT_ENCODE_FUNCTIONS(LivestreamDriverEncode),
|
||||
};
|
||||
|
||||
const EncoderInfo qcam_encoder_info = {
|
||||
.publish_name = "qRoadEncodeData",
|
||||
.filename = "qcamera.ts",
|
||||
.settings = EncoderSettings::QcamEncoderSettings(),
|
||||
.get_settings = [](int){return EncoderSettings::QcamEncoderSettings();},
|
||||
.frame_width = 526,
|
||||
.frame_height = 330,
|
||||
.include_audio = Params().getBool("RecordAudio"),
|
||||
|
||||
@@ -19,11 +19,12 @@ from openpilot.system.hardware.hw import Paths
|
||||
|
||||
SEGMENT_LENGTH = 2
|
||||
FULL_SIZE = 2507572
|
||||
def hevc_size(w): return FULL_SIZE // 2 if w <= 1344 else FULL_SIZE
|
||||
CAMERAS = [
|
||||
("fcamera.hevc", 20, FULL_SIZE, "roadEncodeIdx"),
|
||||
("dcamera.hevc", 20, FULL_SIZE, "driverEncodeIdx"),
|
||||
("ecamera.hevc", 20, FULL_SIZE, "wideRoadEncodeIdx"),
|
||||
("qcamera.ts", 20, 130000, None),
|
||||
("fcamera.hevc", 20, hevc_size, "roadEncodeIdx"),
|
||||
("dcamera.hevc", 20, hevc_size, "driverEncodeIdx"),
|
||||
("ecamera.hevc", 20, hevc_size, "wideRoadEncodeIdx"),
|
||||
("qcamera.ts", 20, lambda x: 130000, None),
|
||||
]
|
||||
|
||||
# we check frame count, so we don't have to be too strict on size
|
||||
@@ -76,7 +77,7 @@ class TestEncoder:
|
||||
# check each camera file size
|
||||
counts = []
|
||||
first_frames = []
|
||||
for camera, fps, size, encode_idx_name in CAMERAS:
|
||||
for camera, fps, size_lambda, encode_idx_name in CAMERAS:
|
||||
if not record_front and "dcamera" in camera:
|
||||
continue
|
||||
|
||||
@@ -86,14 +87,14 @@ class TestEncoder:
|
||||
assert os.path.exists(file_path), f"segment #{i}: '{file_path}' missing"
|
||||
|
||||
# TODO: this ffprobe call is really slow
|
||||
# check frame count
|
||||
cmd = f"ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 {file_path}"
|
||||
# get width and check frame count
|
||||
cmd = f"ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets,width -of csv=p=0 {file_path}"
|
||||
if TICI:
|
||||
cmd = "LD_LIBRARY_PATH=/usr/local/lib " + cmd
|
||||
|
||||
expected_frames = fps * SEGMENT_LENGTH
|
||||
probe = subprocess.check_output(cmd, shell=True, encoding='utf8')
|
||||
frame_count = int(probe.split('\n')[0].strip())
|
||||
probe = subprocess.check_output(cmd, shell=True, encoding='utf8').split('\n')[0].strip().split(',')
|
||||
frame_width, frame_count = int(probe[0]), int(probe[1])
|
||||
counts.append(frame_count)
|
||||
|
||||
assert frame_count == expected_frames, \
|
||||
@@ -101,8 +102,9 @@ class TestEncoder:
|
||||
|
||||
# sanity check file size
|
||||
file_size = os.path.getsize(file_path)
|
||||
assert math.isclose(file_size, size, rel_tol=FILE_SIZE_TOLERANCE), \
|
||||
f"{file_path} size {file_size} isn't close to target size {size}"
|
||||
target_size = size_lambda(frame_width)
|
||||
assert math.isclose(file_size, target_size, rel_tol=FILE_SIZE_TOLERANCE), \
|
||||
f"{file_path} size {file_size} isn't close to target size {target_size}"
|
||||
|
||||
# Check encodeIdx
|
||||
if encode_idx_name is not None:
|
||||
|
||||
Reference in New Issue
Block a user