mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-07-16 19:32:12 +08:00
+1
-1
@@ -40,7 +40,7 @@ assert arch in [
|
||||
"Darwin", # macOS arm64 (x86 not supported)
|
||||
]
|
||||
|
||||
pkg_names = ['acados', 'bzip2', 'capnproto', 'catch2', 'eigen', 'ffmpeg', 'json11', 'libyuv', 'ncurses', 'zeromq', 'zstd']
|
||||
pkg_names = ['acados', 'bzip2', 'capnproto', 'catch2', 'eigen', 'ffmpeg', 'json11', 'ncurses', 'zeromq', 'zstd']
|
||||
pkgs = [importlib.import_module(name) for name in pkg_names]
|
||||
acados = pkgs[pkg_names.index('acados')]
|
||||
ffmpeg = pkgs[pkg_names.index('ffmpeg')]
|
||||
|
||||
@@ -5,6 +5,7 @@ common_libs = [
|
||||
'swaglog.cc',
|
||||
'util.cc',
|
||||
'ratekeeper.cc',
|
||||
'yuv.cc',
|
||||
]
|
||||
|
||||
_common = env.Library('common', common_libs, LIBS="json11")
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
#include "common/yuv.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace yuv {
|
||||
|
||||
namespace {
|
||||
|
||||
inline uint8_t clamp_u8(int v) {
|
||||
return static_cast<uint8_t>(std::clamp(v, 0, 255));
|
||||
}
|
||||
|
||||
void copy_plane(const uint8_t *src, int src_stride,
|
||||
uint8_t *dst, int dst_stride,
|
||||
int width, int height) {
|
||||
if (src_stride == width && dst_stride == width) {
|
||||
std::memcpy(dst, src, static_cast<size_t>(width) * height);
|
||||
return;
|
||||
}
|
||||
for (int y = 0; y < height; ++y) {
|
||||
std::memcpy(dst + y * dst_stride, src + y * src_stride, width);
|
||||
}
|
||||
}
|
||||
|
||||
void scale_plane_point(const uint8_t *src, int src_stride, int src_width, int src_height,
|
||||
uint8_t *dst, int dst_stride, int dst_width, int dst_height) {
|
||||
if (src_width == dst_width && src_height == dst_height) {
|
||||
copy_plane(src, src_stride, dst, dst_stride, dst_width, dst_height);
|
||||
return;
|
||||
}
|
||||
for (int y = 0; y < dst_height; ++y) {
|
||||
const int sy = y * src_height / dst_height;
|
||||
const uint8_t *src_row = src + sy * src_stride;
|
||||
uint8_t *dst_row = dst + y * dst_stride;
|
||||
for (int x = 0; x < dst_width; ++x) {
|
||||
dst_row[x] = src_row[x * src_width / dst_width];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BT.601 limited range → RGB (integer form used widely, incl. similar to libyuv).
|
||||
inline void yuv_to_rgb(int y, int u, int v, uint8_t *r, uint8_t *g, uint8_t *b) {
|
||||
const int c = (y - 16) * 298;
|
||||
const int d = u - 128;
|
||||
const int e = v - 128;
|
||||
*r = clamp_u8((c + 409 * e + 128) >> 8);
|
||||
*g = clamp_u8((c - 100 * d - 208 * e + 128) >> 8);
|
||||
*b = clamp_u8((c + 516 * d + 128) >> 8);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void nv12_to_i420(const uint8_t *src_y, int src_stride_y,
|
||||
const uint8_t *src_uv, int src_stride_uv,
|
||||
uint8_t *dst_y, int dst_stride_y,
|
||||
uint8_t *dst_u, int dst_stride_u,
|
||||
uint8_t *dst_v, int dst_stride_v,
|
||||
int width, int height) {
|
||||
copy_plane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
|
||||
|
||||
const int uv_width = width / 2;
|
||||
const int uv_height = height / 2;
|
||||
for (int y = 0; y < uv_height; ++y) {
|
||||
const uint8_t *uv = src_uv + y * src_stride_uv;
|
||||
uint8_t *u = dst_u + y * dst_stride_u;
|
||||
uint8_t *v = dst_v + y * dst_stride_v;
|
||||
for (int x = 0; x < uv_width; ++x) {
|
||||
u[x] = uv[2 * x];
|
||||
v[x] = uv[2 * x + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void i420_to_nv12(const uint8_t *src_y, int src_stride_y,
|
||||
const uint8_t *src_u, int src_stride_u,
|
||||
const uint8_t *src_v, int src_stride_v,
|
||||
uint8_t *dst_y, int dst_stride_y,
|
||||
uint8_t *dst_uv, int dst_stride_uv,
|
||||
int width, int height) {
|
||||
copy_plane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
|
||||
|
||||
const int uv_width = width / 2;
|
||||
const int uv_height = height / 2;
|
||||
for (int y = 0; y < uv_height; ++y) {
|
||||
const uint8_t *u = src_u + y * src_stride_u;
|
||||
const uint8_t *v = src_v + y * src_stride_v;
|
||||
uint8_t *uv = dst_uv + y * dst_stride_uv;
|
||||
for (int x = 0; x < uv_width; ++x) {
|
||||
uv[2 * x] = u[x];
|
||||
uv[2 * x + 1] = v[x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void i420_scale(const uint8_t *src_y, int src_stride_y,
|
||||
const uint8_t *src_u, int src_stride_u,
|
||||
const uint8_t *src_v, int src_stride_v,
|
||||
int src_width, int src_height,
|
||||
uint8_t *dst_y, int dst_stride_y,
|
||||
uint8_t *dst_u, int dst_stride_u,
|
||||
uint8_t *dst_v, int dst_stride_v,
|
||||
int dst_width, int dst_height) {
|
||||
scale_plane_point(src_y, src_stride_y, src_width, src_height,
|
||||
dst_y, dst_stride_y, dst_width, dst_height);
|
||||
scale_plane_point(src_u, src_stride_u, src_width / 2, src_height / 2,
|
||||
dst_u, dst_stride_u, dst_width / 2, dst_height / 2);
|
||||
scale_plane_point(src_v, src_stride_v, src_width / 2, src_height / 2,
|
||||
dst_v, dst_stride_v, dst_width / 2, dst_height / 2);
|
||||
}
|
||||
|
||||
void nv12_to_rgba(const uint8_t *src_y, int src_stride_y,
|
||||
const uint8_t *src_uv, int src_stride_uv,
|
||||
uint8_t *dst_rgba, int dst_stride_rgba,
|
||||
int width, int height) {
|
||||
for (int y = 0; y < height; ++y) {
|
||||
const uint8_t *y_row = src_y + y * src_stride_y;
|
||||
const uint8_t *uv_row = src_uv + (y / 2) * src_stride_uv;
|
||||
uint8_t *dst = dst_rgba + y * dst_stride_rgba;
|
||||
for (int x = 0; x < width; ++x) {
|
||||
const int uv_x = (x & ~1);
|
||||
uint8_t r, g, b;
|
||||
yuv_to_rgb(y_row[x], uv_row[uv_x], uv_row[uv_x + 1], &r, &g, &b);
|
||||
dst[4 * x + 0] = r;
|
||||
dst[4 * x + 1] = g;
|
||||
dst[4 * x + 2] = b;
|
||||
dst[4 * x + 3] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace yuv
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// NV12: Y plane + interleaved UV. I420: planar Y, U, V.
|
||||
|
||||
namespace yuv {
|
||||
|
||||
// Deinterleave NV12 UV into planar I420.
|
||||
void nv12_to_i420(const uint8_t *src_y, int src_stride_y,
|
||||
const uint8_t *src_uv, int src_stride_uv,
|
||||
uint8_t *dst_y, int dst_stride_y,
|
||||
uint8_t *dst_u, int dst_stride_u,
|
||||
uint8_t *dst_v, int dst_stride_v,
|
||||
int width, int height);
|
||||
|
||||
// Interleave planar I420 UV into NV12.
|
||||
void i420_to_nv12(const uint8_t *src_y, int src_stride_y,
|
||||
const uint8_t *src_u, int src_stride_u,
|
||||
const uint8_t *src_v, int src_stride_v,
|
||||
uint8_t *dst_y, int dst_stride_y,
|
||||
uint8_t *dst_uv, int dst_stride_uv,
|
||||
int width, int height);
|
||||
|
||||
// Point-sample scale I420 (equivalent to libyuv::I420Scale + kFilterNone).
|
||||
void i420_scale(const uint8_t *src_y, int src_stride_y,
|
||||
const uint8_t *src_u, int src_stride_u,
|
||||
const uint8_t *src_v, int src_stride_v,
|
||||
int src_width, int src_height,
|
||||
uint8_t *dst_y, int dst_stride_y,
|
||||
uint8_t *dst_u, int dst_stride_u,
|
||||
uint8_t *dst_v, int dst_stride_v,
|
||||
int dst_width, int dst_height);
|
||||
|
||||
// Convert NV12 to packed RGBA (R,G,B,A bytes — suitable for GL_RGBA).
|
||||
// BT.601 limited-range, matching common libyuv defaults.
|
||||
void nv12_to_rgba(const uint8_t *src_y, int src_stride_y,
|
||||
const uint8_t *src_uv, int src_stride_uv,
|
||||
uint8_t *dst_rgba, int dst_stride_rgba,
|
||||
int width, int height);
|
||||
|
||||
}
|
||||
@@ -8,7 +8,6 @@ if arch == "larch64":
|
||||
src += ['encoder/v4l_encoder.cc']
|
||||
else:
|
||||
src += ['encoder/ffmpeg_encoder.cc']
|
||||
libs += ['yuv']
|
||||
if arch == "Darwin":
|
||||
frameworks += ['VideoToolbox', 'CoreMedia', 'CoreFoundation', 'CoreVideo']
|
||||
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
|
||||
#include "libyuv.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
@@ -19,6 +17,7 @@ extern "C" {
|
||||
|
||||
#include "common/swaglog.h"
|
||||
#include "common/util.h"
|
||||
#include "common/yuv.h"
|
||||
|
||||
const int env_debug_encoder = (getenv("DEBUG_ENCODER") != NULL) ? atoi(getenv("DEBUG_ENCODER")) : 0;
|
||||
|
||||
@@ -87,26 +86,25 @@ int FfmpegEncoder::encode_frame(VisionBuf* buf, VisionIpcBufExtra *extra) {
|
||||
uint8_t *cy = convert_buf.data();
|
||||
uint8_t *cu = cy + in_width * in_height;
|
||||
uint8_t *cv = cu + (in_width / 2) * (in_height / 2);
|
||||
libyuv::NV12ToI420(buf->y, buf->stride,
|
||||
buf->uv, buf->stride,
|
||||
cy, in_width,
|
||||
cu, in_width/2,
|
||||
cv, in_width/2,
|
||||
in_width, in_height);
|
||||
yuv::nv12_to_i420(buf->y, buf->stride,
|
||||
buf->uv, buf->stride,
|
||||
cy, in_width,
|
||||
cu, in_width/2,
|
||||
cv, in_width/2,
|
||||
in_width, in_height);
|
||||
|
||||
if (downscale_buf.size() > 0) {
|
||||
uint8_t *out_y = downscale_buf.data();
|
||||
uint8_t *out_u = out_y + frame->width * frame->height;
|
||||
uint8_t *out_v = out_u + (frame->width / 2) * (frame->height / 2);
|
||||
libyuv::I420Scale(cy, in_width,
|
||||
cu, in_width/2,
|
||||
cv, in_width/2,
|
||||
in_width, in_height,
|
||||
out_y, frame->width,
|
||||
out_u, frame->width/2,
|
||||
out_v, frame->width/2,
|
||||
frame->width, frame->height,
|
||||
libyuv::kFilterNone);
|
||||
yuv::i420_scale(cy, in_width,
|
||||
cu, in_width/2,
|
||||
cv, in_width/2,
|
||||
in_width, in_height,
|
||||
out_y, frame->width,
|
||||
out_u, frame->width/2,
|
||||
out_v, frame->width/2,
|
||||
frame->width, frame->height);
|
||||
frame->data[0] = out_y;
|
||||
frame->data[1] = out_u;
|
||||
frame->data[2] = out_v;
|
||||
|
||||
@@ -75,7 +75,7 @@ cabana_env = qt_env.Clone()
|
||||
cabana_env['CPPPATH'] += [libusb.INCLUDE_DIR]
|
||||
cabana_env['LIBPATH'] += [libusb.LIB_DIR]
|
||||
|
||||
cabana_libs = [cereal, messaging, visionipc, replay_lib] + ffmpeg_libs + ['bz2', 'zstd', 'yuv', 'usb-1.0'] + base_libs
|
||||
cabana_libs = [cereal, messaging, visionipc, replay_lib] + ffmpeg_libs + ['bz2', 'zstd', 'usb-1.0'] + base_libs
|
||||
opendbc_path = '-DOPENDBC_FILE_PATH=\'"%s"\'' % (cabana_env.Dir("../../../opendbc/dbc").abspath)
|
||||
cabana_env['CXXFLAGS'] += [opendbc_path]
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ event_extractors = jot_env.Command("generated_event_extractors.h", [
|
||||
)
|
||||
|
||||
libs = [replay_lib, common, messaging, visionipc, cereal, File(f"{imgui.LIB_DIR}/libimgui.a"), File(f"{imgui.LIB_DIR}/libglfw3.a")] + \
|
||||
ffmpeg_libs + ["yuv", "bz2", "zstd", "m", "pthread", "usb-1.0"]
|
||||
ffmpeg_libs + ["bz2", "zstd", "m", "pthread", "usb-1.0"]
|
||||
if arch == "Darwin":
|
||||
jot_env["FRAMEWORKS"] = ["OpenGL", "Cocoa", "IOKit", "CoreFoundation", "CoreVideo", "CoreMedia", "VideoToolbox"]
|
||||
else:
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include "imgui_impl_opengl3_loader.h"
|
||||
#include "implot.h"
|
||||
#include "libyuv.h"
|
||||
#include "common/yuv.h"
|
||||
#include "msgq_repo/msgq/ipc.h"
|
||||
#include "tools/replay/framereader.h"
|
||||
|
||||
@@ -1173,14 +1173,14 @@ struct CameraFeedView::Impl {
|
||||
result.width = reader->width;
|
||||
result.height = reader->height;
|
||||
result.rgba.resize(static_cast<size_t>(result.width) * static_cast<size_t>(result.height) * 4U, 0);
|
||||
libyuv::NV12ToABGR(decode_buffer.y,
|
||||
static_cast<int>(decode_buffer.stride),
|
||||
decode_buffer.uv,
|
||||
static_cast<int>(decode_buffer.stride),
|
||||
result.rgba.data(),
|
||||
result.width * 4,
|
||||
result.width,
|
||||
result.height);
|
||||
yuv::nv12_to_rgba(decode_buffer.y,
|
||||
static_cast<int>(decode_buffer.stride),
|
||||
decode_buffer.uv,
|
||||
static_cast<int>(decode_buffer.stride),
|
||||
result.rgba.data(),
|
||||
result.width * 4,
|
||||
result.width,
|
||||
result.height);
|
||||
result.success = true;
|
||||
result.decode_ms = std::chrono::duration<double, std::milli>(std::chrono::steady_clock::now() - decode_begin).count();
|
||||
publish_result(*request, std::move(result));
|
||||
@@ -1203,14 +1203,14 @@ struct CameraFeedView::Impl {
|
||||
.height = reader->height,
|
||||
};
|
||||
prefetched.rgba.resize(static_cast<size_t>(prefetched.width) * static_cast<size_t>(prefetched.height) * 4U, 0);
|
||||
libyuv::NV12ToABGR(decode_buffer.y,
|
||||
static_cast<int>(decode_buffer.stride),
|
||||
decode_buffer.uv,
|
||||
static_cast<int>(decode_buffer.stride),
|
||||
prefetched.rgba.data(),
|
||||
prefetched.width * 4,
|
||||
prefetched.width,
|
||||
prefetched.height);
|
||||
yuv::nv12_to_rgba(decode_buffer.y,
|
||||
static_cast<int>(decode_buffer.stride),
|
||||
decode_buffer.uv,
|
||||
static_cast<int>(decode_buffer.stride),
|
||||
prefetched.rgba.data(),
|
||||
prefetched.width * 4,
|
||||
prefetched.width,
|
||||
prefetched.height);
|
||||
remember_cached_result(prefetched);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ if arch != "Darwin":
|
||||
replay_lib_src.append("qcom_decoder.cc")
|
||||
replay_lib = replay_env.Library("replay", replay_lib_src, LIBS=base_libs, FRAMEWORKS=base_frameworks)
|
||||
Export('replay_lib')
|
||||
replay_libs = [replay_lib] + ffmpeg_libs + ['bz2', 'zstd', 'yuv', 'ncurses'] + base_libs
|
||||
replay_libs = [replay_lib] + ffmpeg_libs + ['bz2', 'zstd', 'ncurses'] + base_libs
|
||||
replay_env.Program("replay", ["main.cc"], LIBS=replay_libs, FRAMEWORKS=base_frameworks)
|
||||
|
||||
if GetOption('extras'):
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "common/util.h"
|
||||
#include "libyuv.h"
|
||||
#include "common/yuv.h"
|
||||
#include "tools/replay/py_downloader.h"
|
||||
#include "tools/replay/util.h"
|
||||
#include "common/hardware/hw.h"
|
||||
@@ -258,12 +258,12 @@ bool FFmpegVideoDecoder::copyBuffer(AVFrame *f, VisionBuf *buf) {
|
||||
memcpy(buf->uv + i*buf->stride, f->data[1] + i*f->linesize[1], width);
|
||||
}
|
||||
} else {
|
||||
libyuv::I420ToNV12(f->data[0], f->linesize[0],
|
||||
f->data[1], f->linesize[1],
|
||||
f->data[2], f->linesize[2],
|
||||
buf->y, buf->stride,
|
||||
buf->uv, buf->stride,
|
||||
width, height);
|
||||
yuv::i420_to_nv12(f->data[0], f->linesize[0],
|
||||
f->data[1], f->linesize[1],
|
||||
f->data[2], f->linesize[2],
|
||||
buf->y, buf->stride,
|
||||
buf->uv, buf->stride,
|
||||
width, height);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ dependencies = [
|
||||
"comma-deps-acados",
|
||||
"comma-deps-eigen",
|
||||
"comma-deps-ffmpeg",
|
||||
"comma-deps-libyuv",
|
||||
"comma-deps-zstd",
|
||||
"comma-deps-ncurses",
|
||||
"comma-deps-zeromq",
|
||||
|
||||
@@ -332,16 +332,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/84/47/f4f2da67db202bacc3fa578fdebdb916f45c97bee0c3d2c5fbe845a6f129/comma_deps_libusb-1.0.29.post93-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:f136dbbfc461d228378731361cc66a90a483e17d55f8ba43f23eeab6bcf41963", size = 93461, upload-time = "2026-07-08T19:32:26.434Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "comma-deps-libyuv"
|
||||
version = "1922.0.post93"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/19/91/f68b07f4ef01860d85e716b5095e10326de74455970cb279d70cdf45ee51/comma_deps_libyuv-1922.0.post93-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f5e0d1550229efdc9aabcaa90b421902322ac7ddadd6e2118596916571c0619b", size = 269554, upload-time = "2026-07-08T19:32:29.709Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/6b/ca7ab7c00a16470f03a25c1079a50a2b7933516584056f15fb05385f377c/comma_deps_libyuv-1922.0.post93-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:3c55195bc905144ef157b8d2f8f36b25250d0a489bb07f2964327e48a0009669", size = 268385, upload-time = "2026-07-08T19:32:33.141Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/9d/ecdbbeef4c3797091ea990bbe4dcc10389e5d6bff27e20bed3b4e4a85eed/comma_deps_libyuv-1922.0.post93-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:1309769c64394294cbd399c77584f7d674753e6dda39b57243ab156711b6d353", size = 273326, upload-time = "2026-07-08T19:32:36.807Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "comma-deps-ncurses"
|
||||
version = "6.5.post93"
|
||||
@@ -1004,7 +994,6 @@ dependencies = [
|
||||
{ name = "comma-deps-git-lfs" },
|
||||
{ name = "comma-deps-json11" },
|
||||
{ name = "comma-deps-libusb" },
|
||||
{ name = "comma-deps-libyuv" },
|
||||
{ name = "comma-deps-ncurses" },
|
||||
{ name = "comma-deps-raylib" },
|
||||
{ name = "comma-deps-zeromq" },
|
||||
@@ -1088,7 +1077,6 @@ requires-dist = [
|
||||
{ name = "comma-deps-imgui", marker = "extra == 'tools'" },
|
||||
{ name = "comma-deps-json11" },
|
||||
{ name = "comma-deps-libusb" },
|
||||
{ name = "comma-deps-libyuv" },
|
||||
{ name = "comma-deps-ncurses" },
|
||||
{ name = "comma-deps-raylib" },
|
||||
{ name = "comma-deps-zeromq" },
|
||||
|
||||
Reference in New Issue
Block a user