diff --git a/plugins/ai_yolo/ai_yolo_node.cpp b/plugins/ai_yolo/ai_yolo_node.cpp index 21d365e..0754296 100644 --- a/plugins/ai_yolo/ai_yolo_node.cpp +++ b/plugins/ai_yolo/ai_yolo_node.cpp @@ -95,11 +95,13 @@ void QuickSortDescending(std::vector& values, int left, int right, std::v void NMS(int valid_count, std::vector& boxes, std::vector& class_ids, std::vector& order, int filter_id, float threshold) { for (int i = 0; i < valid_count; ++i) { - if (order[i] == -1 || class_ids[i] != filter_id) continue; int n = order[i]; + if (n < 0 || n >= valid_count) continue; + if (class_ids[n] != filter_id) continue; for (int j = i + 1; j < valid_count; ++j) { int m = order[j]; - if (m == -1 || class_ids[j] != filter_id) continue; + if (m < 0 || m >= valid_count) continue; + if (class_ids[m] != filter_id) continue; float x1_min = boxes[n * 4 + 0]; float y1_min = boxes[n * 4 + 1]; float x1_max = x1_min + boxes[n * 4 + 2]; diff --git a/plugins/preprocess/preprocess_node.cpp b/plugins/preprocess/preprocess_node.cpp index 0968dd6..889b665 100644 --- a/plugins/preprocess/preprocess_node.cpp +++ b/plugins/preprocess/preprocess_node.cpp @@ -62,6 +62,127 @@ size_t CalcImageSize(int w, int h, PixelFormat fmt) { } } +size_t CalcImageSizeStrided(int wstride, int hstride, PixelFormat fmt) { + if (wstride <= 0 || hstride <= 0) return 0; + const size_t ws = static_cast(wstride); + const size_t hs = static_cast(hstride); + switch (fmt) { + case PixelFormat::NV12: { + // Y: ws*hs, UV: ws*(hs/2) + return ws * hs + ws * (hs / 2); + } + case PixelFormat::YUV420: { + // Y: ws*hs, U/V: (ws/2)*(hs/2) + const size_t y = ws * hs; + const size_t uv = (ws / 2) * (hs / 2); + return y + uv + uv; + } + case PixelFormat::RGB: + case PixelFormat::BGR: + return ws * hs * 3; + default: + return 0; + } +} + +bool CopyToStridedBuffer(const Frame& src, uint8_t* dst, size_t dst_size, + int dst_wstride, int dst_hstride) { + if (!dst || dst_size == 0) return false; + if (dst_wstride <= 0 || dst_hstride <= 0) return false; + + std::memset(dst, 0, dst_size); + + const int w = src.width; + const int h = src.height; + if (w <= 0 || h <= 0) return false; + + if (src.format == PixelFormat::NV12) { + const size_t y_bytes = static_cast(dst_wstride) * dst_hstride; + const size_t uv_bytes = static_cast(dst_wstride) * (dst_hstride / 2); + if (y_bytes + uv_bytes > dst_size) return false; + + const uint8_t* src_y = src.planes[0].data ? src.planes[0].data : src.data; + const uint8_t* src_uv = src.planes[1].data ? src.planes[1].data : nullptr; + const int src_y_stride = src.planes[0].stride > 0 ? src.planes[0].stride : w; + const int src_uv_stride = src.planes[1].stride > 0 ? src.planes[1].stride : w; + if (!src_y || !src_uv) return false; + + for (int row = 0; row < h; ++row) { + std::memcpy(dst + static_cast(row) * dst_wstride, + src_y + static_cast(row) * src_y_stride, + static_cast(w)); + } + + uint8_t* dst_uv = dst + y_bytes; + const int uv_rows = h / 2; + for (int row = 0; row < uv_rows; ++row) { + std::memcpy(dst_uv + static_cast(row) * dst_wstride, + src_uv + static_cast(row) * src_uv_stride, + static_cast(w)); + } + return true; + } + + if (src.format == PixelFormat::YUV420) { + const size_t y_bytes = static_cast(dst_wstride) * dst_hstride; + const size_t uv_stride = static_cast(dst_wstride) / 2; + const size_t uv_h = static_cast(dst_hstride) / 2; + const size_t u_bytes = uv_stride * uv_h; + const size_t v_bytes = u_bytes; + if (y_bytes + u_bytes + v_bytes > dst_size) return false; + + const uint8_t* src_y = src.planes[0].data ? src.planes[0].data : src.data; + const uint8_t* src_u = src.planes[1].data ? src.planes[1].data : nullptr; + const uint8_t* src_v = src.planes[2].data ? src.planes[2].data : nullptr; + const int src_y_stride = src.planes[0].stride > 0 ? src.planes[0].stride : w; + const int src_u_stride = src.planes[1].stride > 0 ? src.planes[1].stride : (w / 2); + const int src_v_stride = src.planes[2].stride > 0 ? src.planes[2].stride : (w / 2); + if (!src_y || !src_u || !src_v) return false; + + for (int row = 0; row < h; ++row) { + std::memcpy(dst + static_cast(row) * dst_wstride, + src_y + static_cast(row) * src_y_stride, + static_cast(w)); + } + + uint8_t* dst_u = dst + y_bytes; + uint8_t* dst_v = dst + y_bytes + u_bytes; + const int uv_rows = h / 2; + const int uv_cols = w / 2; + for (int row = 0; row < uv_rows; ++row) { + std::memcpy(dst_u + static_cast(row) * uv_stride, + src_u + static_cast(row) * src_u_stride, + static_cast(uv_cols)); + std::memcpy(dst_v + static_cast(row) * uv_stride, + src_v + static_cast(row) * src_v_stride, + static_cast(uv_cols)); + } + return true; + } + + if (src.format == PixelFormat::RGB || src.format == PixelFormat::BGR) { + const size_t need = static_cast(dst_wstride) * dst_hstride * 3; + if (need > dst_size) return false; + + const uint8_t* src_rgb = src.planes[0].data ? src.planes[0].data : src.data; + const int src_stride = src.planes[0].stride > 0 + ? src.planes[0].stride + : (src.stride > 0 ? src.stride : w * 3); + if (!src_rgb) return false; + + const size_t dst_stride = static_cast(dst_wstride) * 3; + const size_t row_bytes = static_cast(w) * 3; + for (int row = 0; row < h; ++row) { + std::memcpy(dst + static_cast(row) * dst_stride, + src_rgb + static_cast(row) * src_stride, + row_bytes); + } + return true; + } + + return false; +} + } // namespace class PreprocessNode : public INode { @@ -181,7 +302,7 @@ private: return; } - size_t out_size = CalcImageSize(out_w, out_h, out_fmt); + size_t out_size = CalcImageSizeStrided(dst_wstride, dst_hstride, out_fmt); if (out_size == 0 || src_fmt_rga == RK_FORMAT_UNKNOWN || dst_fmt_rga == RK_FORMAT_UNKNOWN) { std::cerr << "[preprocess] unsupported format for RGA\n"; PushToDownstream(frame); @@ -223,14 +344,18 @@ private: src_wstride, src_hstride, src_fmt_rga); } else if (frame->data) { // Source doesn't have DMA fd, copy to DMA buffer first to avoid >4GB address issue - size_t src_size = CalcImageSize(frame->width, frame->height, frame->format); + size_t src_size = CalcImageSizeStrided(src_wstride, src_hstride, frame->format); src_dma_buf = DmaAlloc(src_size); if (!src_dma_buf || !src_dma_buf->valid()) { std::cerr << "[preprocess] DMA alloc for src failed\n"; PushToDownstream(frame); return; } - memcpy(src_dma_buf->data(), frame->data, std::min(src_size, frame->data_size)); + if (!CopyToStridedBuffer(*frame, src_dma_buf->data(), src_dma_buf->size, src_wstride, src_hstride)) { + std::cerr << "[preprocess] copy src to DMA failed\n"; + PushToDownstream(frame); + return; + } src_buf = wrapbuffer_fd_t(src_dma_buf->fd, frame->width, frame->height, src_wstride, src_hstride, src_fmt_rga); } else { @@ -246,7 +371,7 @@ private: if (need_resize && need_cvt) { // Allocate DMA buffer for intermediate result - auto tmp_dma = DmaAlloc(CalcImageSize(out_w, out_h, frame->format)); + auto tmp_dma = DmaAlloc(CalcImageSizeStrided(dst_wstride, dst_hstride, frame->format)); if (!tmp_dma || !tmp_dma->valid()) { std::cerr << "[preprocess] DMA alloc for tmp failed\n"; PushToDownstream(frame); @@ -274,7 +399,9 @@ private: out_frame->width = out_w; out_frame->height = out_h; out_frame->format = out_fmt; - out_frame->stride = dst_wstride; + out_frame->stride = (out_fmt == PixelFormat::RGB || out_fmt == PixelFormat::BGR) + ? (dst_wstride * 3) + : dst_wstride; out_frame->dma_fd = dma_buf->fd; out_frame->data = dma_buf->data(); out_frame->data_size = dma_buf->size; @@ -355,7 +482,9 @@ private: out_frame->width = out_w; out_frame->height = out_h; out_frame->format = out_fmt; - out_frame->stride = out_w; + out_frame->stride = (out_fmt == PixelFormat::RGB || out_fmt == PixelFormat::BGR) + ? (out_w * 3) + : out_w; out_frame->data = buffer->data(); out_frame->data_size = buffer->size(); out_frame->data_owner = buffer; @@ -409,22 +538,74 @@ private: #endif void SetupPlanes(Frame& f, PixelFormat fmt) { + if (!f.data) return; + if (fmt == PixelFormat::NV12) { f.plane_count = 2; - int y_size = f.width * f.height; - f.planes[0] = {f.data, f.width, y_size, 0}; - f.planes[1] = {f.data + y_size, f.width, y_size / 2, y_size}; - } else if (fmt == PixelFormat::YUV420) { - f.plane_count = 3; - int y_size = f.width * f.height; - int uv_size = y_size / 4; - f.planes[0] = {f.data, f.width, y_size, 0}; - f.planes[1] = {f.data + y_size, f.width / 2, uv_size, y_size}; - f.planes[2] = {f.data + y_size + uv_size, f.width / 2, uv_size, y_size + uv_size}; - } else { - f.plane_count = 1; - f.planes[0] = {f.data, f.width * 3, static_cast(f.data_size), 0}; + int y_stride = f.stride > 0 ? f.stride : f.width; + if (y_stride <= 0) y_stride = f.width; + + size_t y_bytes = static_cast(y_stride) * static_cast(f.height); + if (f.data_size > 0) { + const size_t candidate = (f.data_size * 2) / 3; // total = Y + UV = Y*3/2 + if (candidate >= y_bytes && candidate <= f.data_size && + (candidate % static_cast(y_stride)) == 0) { + y_bytes = candidate; + } + } + + size_t uv_bytes = y_bytes / 2; + if (f.data_size > 0 && y_bytes + uv_bytes > f.data_size) { + uv_bytes = f.data_size > y_bytes ? (f.data_size - y_bytes) : 0; + } + + f.planes[0] = {f.data, y_stride, static_cast(y_bytes), 0}; + f.planes[1] = {f.data + y_bytes, y_stride, static_cast(uv_bytes), static_cast(y_bytes)}; + return; } + + if (fmt == PixelFormat::YUV420) { + f.plane_count = 3; + int y_stride = f.stride > 0 ? f.stride : f.width; + if (y_stride <= 0) y_stride = f.width; + + size_t y_bytes = static_cast(y_stride) * static_cast(f.height); + size_t hstride = static_cast(f.height); + if (f.data_size > 0) { + const size_t candidate = (f.data_size * 2) / 3; + if (candidate >= y_bytes && candidate <= f.data_size && + (candidate % static_cast(y_stride)) == 0) { + y_bytes = candidate; + hstride = y_bytes / static_cast(y_stride); + } + } + + size_t uv_stride = static_cast(y_stride) / 2; + size_t uv_h = hstride / 2; + size_t u_bytes = uv_stride * uv_h; + size_t v_bytes = u_bytes; + size_t need = y_bytes + u_bytes + v_bytes; + + if (f.data_size > 0 && need > f.data_size) { + // Fallback to tightly packed layout. + y_stride = f.width; + y_bytes = static_cast(f.width) * static_cast(f.height); + uv_stride = static_cast(f.width) / 2; + uv_h = static_cast(f.height) / 2; + u_bytes = uv_stride * uv_h; + v_bytes = u_bytes; + } + + f.planes[0] = {f.data, y_stride, static_cast(y_bytes), 0}; + f.planes[1] = {f.data + y_bytes, static_cast(uv_stride), static_cast(u_bytes), static_cast(y_bytes)}; + f.planes[2] = {f.data + y_bytes + u_bytes, static_cast(uv_stride), static_cast(v_bytes), static_cast(y_bytes + u_bytes)}; + return; + } + + // RGB/BGR + f.plane_count = 1; + int stride_bytes = f.stride > 0 ? f.stride : (f.width * 3); + f.planes[0] = {f.data, stride_bytes, static_cast(f.data_size), 0}; } std::string id_;