Merge remote-tracking branch 'upstream/master' into no-capnp-cars-simple

pull/33208/head
Shane Smiskol 1 year ago
commit daf3ff7b2b
  1. 22
      docs/CONTRIBUTING.md
  2. 2
      selfdrive/car/honda/interface.py
  3. 2
      selfdrive/controls/lib/longitudinal_mpc_lib/SConscript
  4. 4
      selfdrive/pandad/panda.cc
  5. 4
      system/hardware/tici/updater
  6. 17
      tools/install_ubuntu_dependencies.sh
  7. 4
      tools/lib/logreader.py
  8. 21
      tools/op.sh
  9. 50
      tools/rerun/README.md
  10. 5
      tools/rerun/camera_reader.py
  11. 96
      tools/rerun/run.py
  12. 9
      tools/rerun/run.sh
  13. 3
      tools/setup.sh
  14. 1
      tools/webcam/camera.py
  15. 10
      tools/webcam/camerad.py

@ -1,6 +1,8 @@
# How to contribute
Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use. Check out our [post about externalization](https://blog.comma.ai/a-2020-theme-externalization/). Development activity is coordinated through our GitHub Issues, [GitHub Discussions](https://github.com/commaai/openpilot/discussions), and [Discord](https://discord.comma.ai).
Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use. Check out our [post about externalization](https://blog.comma.ai/a-2020-theme-externalization/).
Development is coordinated through [Discord](https://discord.comma.ai) and GitHub.
### Getting Started
@ -11,7 +13,8 @@ Our software is open source so you can solve your own problems without needing h
## What contributions are we looking for?
**openpilot's priorities are [safety](SAFETY.md), stability, quality, and features, in that order.** openpilot is part of comma's mission to *solve self-driving cars while delivering shippable intermediaries*, and **all** development is towards that goal.
**openpilot's priorities are [safety](SAFETY.md), stability, quality, and features, in that order.**
openpilot is part of comma's mission to *solve self-driving cars while delivering shippable intermediaries*, and all development is towards that goal.
### What gets merged?
@ -27,24 +30,21 @@ All of these are examples of good PRs:
### What doesn't get merged?
* **arbitrary style changes**: code is art, and it's up to the author to make it beautiful
* **style changes**: code is art, and it's up to the author to make it beautiful
* **500+ line PRs**: clean it up, break it up into smaller PRs, or both
* **PRs without a clear goal**: every PR must have a singular and clear goal
* **UI design changes**: we do not have a good review process for this yet
* **UI design**: we do not have a good review process for this yet
* **New features**: We believe openpilot is mostly feature-complete, and the rest is a matter of refinement and fixing bugs. As a result of this, most feature PRs will be immediately closed, however the beauty of open source is that forks can and do offer features that upstream openpilot doesn't.
* **Negative expected value**: This a class of PRs that makes an improvement, but the risk or validation costs more than the improvement. The risk can be mitigated by first getting a failing test merged.
### First contribution
Check out any [good first issue](https://github.com/commaai/openpilot/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) to get started.
### What do I need to contribute?
A lot of openpilot work requires only a PC, and some requires a comma device.
Most car-related contributions require access to that car, plus a comma device installed in the car.
[Bounties](https://comma.ai/bounties) are the best place to get started.
There's lot of bounties that don't require a comma 3/3X or a car.
## Pull Requests
Pull requests should be against the master branch. If you're unsure about a contribution, feel free to open a discussion, issue, or draft PR to discuss the problem you're trying to solve.
Pull requests should be against the master branch.
A good pull request has all of the following:
* a clearly stated purpose

@ -209,7 +209,7 @@ class CarInterface(CarInterfaceBase):
# to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not
# conflict with PCM acc
ret.autoResumeSng = candidate in (HONDA_BOSCH | {CAR.HONDA_CIVIC})
ret.minEnableSpeed = -1. if ret.autoResumeSng else 25.5 * CV.MPH_TO_MS
ret.minEnableSpeed = -1. if ret.autoResumeSng else 25.51 * CV.MPH_TO_MS
ret.steerActuatorDelay = 0.1
ret.steerLimitTimer = 0.8

@ -73,6 +73,8 @@ lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES")
lenv["CCFLAGS"].append("-Wno-unused")
if arch != "Darwin":
lenv["LINKFLAGS"].append("-Wl,--disable-new-dtags")
else:
lenv["LINKFLAGS"].append("-Wl,-install_name,@loader_path/libacados_ocp_solver_long.dylib")
lib_solver = lenv.SharedLibrary(f"{gen}/acados_ocp_solver_long",
build_files,
LIBS=['m', 'acados', 'hpipm', 'blasfeo', 'qpOASES_e'])

@ -10,6 +10,8 @@
#include "common/swaglog.h"
#include "common/util.h"
const bool PANDAD_MAXOUT = getenv("PANDAD_MAXOUT") != nullptr;
Panda::Panda(std::string serial, uint32_t bus_offset) : bus_offset(bus_offset) {
// try USB first, then SPI
try {
@ -219,7 +221,7 @@ bool Panda::can_receive(std::vector<can_frame>& out_vec) {
return false;
}
if (getenv("PANDAD_MAXOUT") != NULL) {
if (PANDAD_MAXOUT) {
static uint8_t junk[RECV_SIZE];
handle->bulk_read(0xab, junk, RECV_SIZE - recv);
}

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f74ea28934c6b9477a98dc6a38e6bfcd53e94e6af31dba5b6d11bc5310f7d995
size 8135168
oid sha256:8db3f973663e59921fcc9e5d5600a346c1e229a2e8481a874ef996d97303dc4e
size 16631712

@ -148,6 +148,23 @@ if [ -f "/etc/os-release" ]; then
if [[ "$INSTALL_EXTRA_PACKAGES" == "yes" ]]; then
install_extra_packages
fi
if [[ -d "/etc/udev/rules.d/" ]]; then
# Setup panda udev rules
$SUDO tee /etc/udev/rules.d/12-panda_jungle.rules > /dev/null <<EOF
SUBSYSTEM=="usb", ATTRS{idVendor}=="bbaa", ATTRS{idProduct}=="ddcf", MODE="0666"
SUBSYSTEM=="usb", ATTRS{idVendor}=="bbaa", ATTRS{idProduct}=="ddef", MODE="0666"
EOF
# Setup jungle udev rules
$SUDO tee /etc/udev/rules.d/11-panda.rules > /dev/null <<EOF
SUBSYSTEM=="usb", ATTRS{idVendor}=="bbaa", ATTRS{idProduct}=="ddcc", MODE="0666"
SUBSYSTEM=="usb", ATTRS{idVendor}=="bbaa", ATTRS{idProduct}=="ddee", MODE="0666"
EOF
$SUDO udevadm control --reload-rules && $SUDO udevadm trigger || true
fi
else
echo "No /etc/os-release in the system. Make sure you're running on Ubuntu, or similar."
exit 1

@ -293,11 +293,11 @@ are uploaded or auto fallback to qlogs with '/a' selector at the end of the rout
def _run_on_segment(self, func, i):
return func(self._get_lr(i))
def run_across_segments(self, num_processes, func):
def run_across_segments(self, num_processes, func, desc=None):
with multiprocessing.Pool(num_processes) as pool:
ret = []
num_segs = len(self.logreader_identifiers)
for p in tqdm.tqdm(pool.imap(partial(self._run_on_segment, func), range(num_segs)), total=num_segs):
for p in tqdm.tqdm(pool.imap(partial(self._run_on_segment, func), range(num_segs)), total=num_segs, desc=desc):
ret.extend(p)
return ret

@ -14,6 +14,7 @@ UNDERLINE='\033[4m'
BOLD='\033[1m'
NC='\033[0m'
SHELL_NAME="$(basename ${SHELL})"
RC_FILE="${HOME}/.$(basename ${SHELL})rc"
if [ "$(uname)" == "Darwin" ] && [ $SHELL == "/bin/bash" ]; then
RC_FILE="$HOME/.bash_profile"
@ -145,7 +146,7 @@ function op_check_python() {
function op_check_venv() {
echo "Checking for venv..."
if source $OPENPILOT_ROOT/.venv/bin/activate; then
if [[ -f $OPENPILOT_ROOT/.venv/bin/activate ]]; then
echo -e " ↳ [${GREEN}${NC}] venv detected."
else
echo -e " ↳ [${RED}${NC}] Can't activate venv in $OPENPILOT_ROOT. Assuming global env!"
@ -223,12 +224,28 @@ function op_setup() {
}
function op_activate_venv() {
# bash 3.2 can't handle this without the 'set +e'
set +e
source $OPENPILOT_ROOT/.venv/bin/activate &> /dev/null || true
set -e
}
function op_venv() {
op_before_cmd
bash --rcfile <(echo "source $RC_FILE; source $OPENPILOT_ROOT/.venv/bin/activate")
if [[ ! -f $OPENPILOT_ROOT/.venv/bin/activate ]]; then
echo -e "No venv found in $OPENPILOT_ROOT"
return 1
fi
case $SHELL_NAME in
"zsh")
ZSHRC_DIR=$(mktemp -d 2>/dev/null || mktemp -d -t 'tmp_zsh')
echo "source $RC_FILE; source $OPENPILOT_ROOT/.venv/bin/activate" >> $ZSHRC_DIR/.zshrc
ZDOTDIR=$ZSHRC_DIR zsh ;;
*)
bash --rcfile <(echo "source $RC_FILE; source $OPENPILOT_ROOT/.venv/bin/activate") ;;
esac
}
function op_check() {

@ -5,53 +5,33 @@ Rerun is a tool to quickly visualize time series data. It supports all openpilot
## Usage
```
usage: run.py [-h] [--demo] [--qcam] [--fcam] [--ecam] [--dcam] [--print_services] [--services [SERVICES ...]] [route_or_segment_name]
usage: run.py [-h] [--demo] [--qcam] [--fcam] [--ecam] [--dcam] [route_or_segment_name]
A helper to run rerun on openpilot routes
positional arguments:
route_or_segment_name
The route or segment name to plot (default: None)
options:
-h, --help show this help message and exit
--demo Use the demo route instead of providing one (default: False)
--qcam Log decimated driving camera (default: False)
--fcam Log driving camera (default: False)
--ecam Log wide camera (default: False)
--dcam Log driver monitoring camera (default: False)
--print_services List out openpilot services (default: False)
--services [SERVICES ...] Specify openpilot services that will be logged. No service will be logged if not specified.
To log all services include 'all' as one of your services (default: [])
--route [ROUTE] The route or segment name to plot (default: None)
-h, --help show this help message and exit
--demo Use the demo route instead of providing one (default: False)
--qcam Show low-res road camera (default: False)
--fcam Show driving camera (default: False)
--ecam Show wide camera (default: False)
--dcam Show driver monitoring camera (default: False)
```
Examples using route name to observe accelerometer and qcamera:
`./run.py --services accelerometer --qcam --route "a2a0ccea32023010/2023-07-27--13-01-19"`
`./run.sh --qcam "a2a0ccea32023010/2023-07-27--13-01-19"`
Examples using segment range (more on [SegmentRange](https://github.com/commaai/openpilot/tree/master/tools/lib)):
`./run.py --qcam --route "a2a0ccea32023010/2023-07-27--13-01-19/2:4"`
`./run.sh --qcam "a2a0ccea32023010/2023-07-27--13-01-19/2:4"`
## Cautions:
- You can specify `--services all` to visualize all `logMessage`, but it will draw a lot of memory usage and take a long time to log all messages. Rerun isn't ready for logging big number of data.
- Logging hevc videos (`--fcam`, `--ecam`, and `--dcam`) are expensive, and it's recommended to use `--qcam` for optimized performance. If possible, limiting your route to a few segments using `SegmentRange` will speed up logging and reduce memory usage
This example draws 13GB of memory:
`./run.py --services accelerometer --qcam --route "a2a0ccea32023010/2023-07-27--13-01-19"`
## Openpilot services
To list all openpilot services:
`./run.py --print_services`
Examples including openpilot services:
`./run.py --services accelerometer cameraodometry --route "a2a0ccea32023010/2023-07-27--13-01-19/0/q"`
Examples including all services:
`./run.py --services all --route "a2a0ccea32023010/2023-07-27--13-01-19/0/q"`
- Showing hevc videos (`--fcam`, `--ecam`, and `--dcam`) are expensive, and it's recommended to use `--qcam` for optimized performance. If possible, limiting your route to a few segments using `SegmentRange` will speed up logging and reduce memory usage
## Demo
`./run.py --services accelerometer carcontrol caroutput --qcam --demo`
`./run.sh --qcam --demo`

@ -37,6 +37,7 @@ class _FrameReader:
frame_sz = self.w * self.h * 3 // 2
proc = subprocess.Popen(
["ffmpeg", "-v", "quiet", "-i", self.camera_path, "-f", "rawvideo", "-pix_fmt", "nv12", "-"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL
)
@ -84,9 +85,9 @@ class CameraReader:
def _run_on_segment(self, func, i):
return func(self._get_fr(i))
def run_across_segments(self, num_processes, func):
def run_across_segments(self, num_processes, func, desc=None):
with multiprocessing.Pool(num_processes) as pool:
num_segs = len(self.seg_idxs)
for _ in tqdm.tqdm(pool.imap_unordered(partial(self._run_on_segment, func), self.seg_idxs), total=num_segs):
for _ in tqdm.tqdm(pool.imap_unordered(partial(self._run_on_segment, func), self.seg_idxs), total=num_segs, desc=desc):
continue

@ -1,10 +1,12 @@
#!/usr/bin/env python3
import sys
import argparse
import multiprocessing
import rerun as rr
import rerun.blueprint as rrb
from functools import partial
from collections import defaultdict
from cereal.services import SERVICE_LIST
from openpilot.tools.rerun.camera_reader import probe_packet_info, CameraReader, CameraConfig, CameraType
@ -20,19 +22,16 @@ RR_WIN = "openpilot logs"
"""
Relevant upstream Rerun issues:
- large time series: https://github.com/rerun-io/rerun/issues/5967
- loading videos directly: https://github.com/rerun-io/rerun/issues/6532
"""
class Rerunner:
def __init__(self, route, segment_range, camera_config, enabled_services):
self.enabled_services = [s.lower() for s in enabled_services]
self.log_all = "all" in self.enabled_services
def __init__(self, route, segment_range, camera_config):
self.lr = LogReader(route_or_segment_name)
# hevc files don't have start_time. We get it from qcamera.ts
start_time = 0
dat = probe_packet_info(r.qcamera_paths()[0])
dat = probe_packet_info(route.qcamera_paths()[0])
for d in dat:
if d.startswith("pts_time="):
start_time = float(d.split('=')[1])
@ -49,34 +48,30 @@ class Rerunner:
if dcam:
self.camera_readers[CameraType.dcam] = CameraReader(route.dcamera_paths(), start_time, segment_range.seg_idxs)
def _start_rerun(self):
self.blueprint = self._create_blueprint()
rr.init(RR_WIN, spawn=True)
def _create_blueprint(self):
blueprint = None
service_views = []
log_msg_visible = len(self.enabled_services) <= 3 and not self.log_all
for topic in sorted(SERVICE_LIST.keys()):
if not self.log_all and topic.lower() not in self.enabled_services:
continue
View = rrb.TimeSeriesView if topic != "thumbnail" else rrb.Spatial2DView
service_views.append(View(name=topic, origin=f"/{topic}/", visible=log_msg_visible))
service_views.append(View(name=topic, origin=f"/{topic}/", visible=False))
rr.log(topic, rr.SeriesLine(name=topic), timeless=True)
center_view = [rrb.Vertical(*service_views, name="streams")]
if len(self.camera_readers):
center_view.append(rrb.Vertical(*[rrb.Spatial2DView(name=cam_type, origin=cam_type) for cam_type in self.camera_readers.keys()], name="cameras"))
blueprint = rrb.Blueprint(
rrb.Horizontal(
rrb.Vertical(*service_views),
rrb.Vertical(*[rrb.Spatial2DView(name=cam_type, origin=cam_type) for cam_type in self.camera_readers.keys()]),
*center_view
),
rrb.SelectionPanel(expanded=False),
rrb.TimePanel(expanded=False)
rrb.TimePanel(expanded=False),
)
return blueprint
@staticmethod
def _log_msg(msg, parent_key=''):
def _parse_msg(msg, parent_key=''):
stack = [(msg, parent_key)]
while stack:
current_msg, current_parent_key = stack.pop()
@ -84,40 +79,47 @@ class Rerunner:
for index, item in enumerate(current_msg):
new_key = f"{current_parent_key}/{index}"
if isinstance(item, (int, float)):
rr.log(new_key, rr.Scalar(item))
yield new_key, item
elif isinstance(item, dict):
stack.append((item, new_key))
elif isinstance(current_msg, dict):
for key, value in current_msg.items():
new_key = f"{current_parent_key}/{key}"
if isinstance(value, (int, float)):
rr.log(new_key, rr.Scalar(value))
yield new_key, value
elif isinstance(value, dict):
stack.append((value, new_key))
elif isinstance(value, list):
for index, item in enumerate(value):
if isinstance(item, (int, float)):
rr.log(f"{new_key}/{index}", rr.Scalar(item))
yield f"{new_key}/{index}", item
else:
pass # Not a plottable value
@staticmethod
@rr.shutdown_at_exit
def _process_log_msgs(blueprint, enabled_services, log_all, lr):
def _process_log_msgs(blueprint, lr):
rr.init(RR_WIN)
rr.connect(default_blueprint=blueprint)
rr.connect()
rr.send_blueprint(blueprint)
log_msgs = defaultdict(lambda: defaultdict(list))
for msg in lr:
rr.set_time_nanos(RR_TIMELINE_NAME, msg.logMonoTime)
msg_type = msg.which()
if not log_all and msg_type.lower() not in enabled_services:
if msg_type == "thumbnail":
continue
if msg_type != "thumbnail":
Rerunner._log_msg(msg.to_dict()[msg.which()], msg.which())
else:
rr.log("/thumbnail", rr.ImageEncoded(contents=msg.to_dict()[msg.which()].get("thumbnail")))
for entity_path, dat in Rerunner._parse_msg(msg.to_dict()[msg_type], msg_type):
log_msgs[entity_path]["times"].append(msg.logMonoTime / 1e9)
log_msgs[entity_path]["data"].append(dat)
for entity_path, log_msg in log_msgs.items():
rr.log_temporal_batch(
entity_path,
times=[rr.TimeSecondsBatch(RR_TIMELINE_NAME, log_msg["times"])],
components=[rr.components.ScalarBatch(log_msg["data"])]
)
return []
@ -125,18 +127,22 @@ class Rerunner:
@rr.shutdown_at_exit
def _process_cam_readers(blueprint, cam_type, h, w, fr):
rr.init(RR_WIN)
rr.connect(default_blueprint=blueprint)
rr.connect()
rr.send_blueprint(blueprint)
for ts, frame in fr:
rr.set_time_nanos(RR_TIMELINE_NAME, int(ts * 1e9))
rr.log(cam_type, rr.Image(bytes=frame, width=w, height=h, pixel_format=rr.PixelFormat.NV12))
def load_data(self):
self._start_rerun()
if len(self.enabled_services) > 0:
self.lr.run_across_segments(NUM_CPUS, partial(self._process_log_msgs, self.blueprint, self.enabled_services, self.log_all))
rr.init(RR_WIN, spawn=True)
startup_blueprint = self._create_blueprint()
self.lr.run_across_segments(NUM_CPUS, partial(self._process_log_msgs, startup_blueprint), desc="Log messages")
for cam_type, cr in self.camera_readers.items():
cr.run_across_segments(NUM_CPUS, partial(self._process_cam_readers, self.blueprint, cam_type, cr.h, cr.w))
cr.run_across_segments(NUM_CPUS, partial(self._process_cam_readers, startup_blueprint, cam_type, cr.h, cr.w), desc=cam_type)
rr.send_blueprint(self._create_blueprint())
if __name__ == '__main__':
@ -147,34 +153,28 @@ if __name__ == '__main__':
parser.add_argument("--fcam", action="store_true", help="Show driving camera")
parser.add_argument("--ecam", action="store_true", help="Show wide camera")
parser.add_argument("--dcam", action="store_true", help="Show driver monitoring camera")
parser.add_argument("--print_services", action="store_true", help="List out openpilot services")
parser.add_argument("--services", default=[], nargs='*', help="Specify openpilot services that will be logged.\
No service will be logged if not specified.\
To log all services include 'all' as one of your services")
parser.add_argument("--route", nargs='?', help="The route or segment name to plot")
parser.add_argument("route_or_segment_name", nargs='?', help="The route or segment name to plot")
args = parser.parse_args()
if not args.demo and not args.route:
if not args.demo and not args.route_or_segment_name:
parser.print_help()
sys.exit()
if args.print_services:
print("\n".join(SERVICE_LIST.keys()))
sys.exit()
camera_config = CameraConfig(args.qcam, args.fcam, args.ecam, args.dcam)
route_or_segment_name = DEMO_ROUTE if args.demo else args.route_or_segment_name.strip()
route_or_segment_name = DEMO_ROUTE if args.demo else args.route.strip()
sr = SegmentRange(route_or_segment_name)
r = Route(sr.route_name)
if len(sr.seg_idxs) > 10:
print("You're requesting more than 10 segments of the route, " + \
"please be aware that might take a lot of memory")
hevc_requested = any(camera_config[1:])
if len(sr.seg_idxs) > 1 and hevc_requested:
print("You're requesting more than 1 segment with hevc videos, " + \
"please be aware that might take a lot of memory " + \
"since rerun isn't yet well supported for high resolution video logging")
response = input("Do you wish to continue? (Y/n): ")
if response.strip().lower() != "y":
sys.exit()
rerunner = Rerunner(r, sr, camera_config, args.services)
rerunner = Rerunner(r, sr, camera_config)
rerunner.load_data()

@ -0,0 +1,9 @@
#! /bin/bash
# TODO: remove this file once Rerun has interface to set log message level
set -e
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
RUST_LOG=warn $DIR/run.py $@

@ -44,6 +44,7 @@ function sentry_send_event() {
PLATFORM=$(uname -s)
ARCH=$(uname -m)
SYSTEM=$(uname -a)
if [[ $PLATFORM == "Darwin" ]]; then
OS="macos"
elif [[ $PLATFORM == "Linux" ]]; then
@ -60,7 +61,7 @@ function sentry_send_event() {
BRANCH=$(echo $(git -C $OPENPILOT_ROOT rev-parse --abbrev-ref HEAD 2> /dev/null || echo "NA"))
COMMIT=$(echo $(git -C $OPENPILOT_ROOT rev-parse HEAD 2> /dev/null || echo "NA"))
curl -s -o /dev/null -X POST -g --data "{ \"exception\": { \"values\": [{ \"type\": \"$EVENT\" }] }, \"tags\" : { \"event_type\" : \"$EVENT_TYPE\", \"event_log\" : \"$EVENT_LOG\", \"os\" : \"$OS\", \"arch\" : \"$ARCH\", \"python_version\" : \"$PYTHON_VERSION\" , \"git_branch\" : \"$BRANCH\", \"git_commit\" : \"$COMMIT\" } }" \
curl -s -o /dev/null -X POST -g --data "{ \"exception\": { \"values\": [{ \"type\": \"$EVENT\" }] }, \"tags\" : { \"event_type\" : \"$EVENT_TYPE\", \"event_log\" : \"$EVENT_LOG\", \"os\" : \"$OS\", \"arch\" : \"$ARCH\", \"python_version\" : \"$PYTHON_VERSION\" , \"git_branch\" : \"$BRANCH\", \"git_commit\" : \"$COMMIT\", \"system\" : \"$SYSTEM\" } }" \
-H 'Content-Type: application/json' \
-H "X-Sentry-Auth: Sentry sentry_version=7, sentry_key=$SENTRY_KEY, sentry_client=op_setup/0.1" \
$SENTRY_URL 2> /dev/null

@ -11,6 +11,7 @@ class Camera:
self.cur_frame_id = 0
self.container = av.open(camera_id)
assert self.container.streams.video, f"Can't open video stream for camera {camera_id}"
self.video_stream = self.container.streams.video[0]
self.W = self.video_stream.codec_context.width
self.H = self.video_stream.codec_context.height

@ -26,7 +26,6 @@ class Camerad:
self.cameras = []
for c in CAMERAS:
cam = Camera(c.msg_name, c.stream_type, c.cam_id)
assert cam.cap.isOpened(), f"Can't find camera {c}"
self.cameras.append(cam)
self.vipc_server.create_buffers(c.stream_type, 20, False, cam.W, cam.H)
@ -47,11 +46,10 @@ class Camerad:
def camera_runner(self, cam):
rk = Ratekeeper(20, None)
while cam.cap.isOpened():
for yuv in cam.read_frames():
self._send_yuv(yuv, cam.cur_frame_id, cam.cam_type_state, cam.stream_type)
cam.cur_frame_id += 1
rk.keep_time()
for yuv in cam.read_frames():
self._send_yuv(yuv, cam.cur_frame_id, cam.cam_type_state, cam.stream_type)
cam.cur_frame_id += 1
rk.keep_time()
def run(self):
threads = []

Loading…
Cancel
Save