第一部分 主测试架构程序 

/**
 * @file main.c
 * @brief 地平线RDK3 AI摄像机主程序
 * @author BSP Team
 * @version 1.0.0
 * 
 * @section 模块集成
 * - 内存管理 (Memory Manager)
 * - 日志系统 (Logger)
 * - 事件循环 (Event Loop)
 * - ISP调优 (ISP Tuning)
 * - AI流水线 (AI Pipeline)
 * - 双架构IPC (IPC Bus)
 * - 时移缓存 (TimeShift Cache)
 * 
 * @section 生命周期
 * 1. 配置加载 -> 2. 模块初始化 -> 3. 资源分配 -> 4. 主循环 -> 5. 优雅退出
 */
​
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <getopt.h>
#include <time.h>
#include <sys/resource.h>
​
/* 地平线RDK3 SDK头文件 */
#include <hb_common.h>
#include <hb_sys.h>
#include <hb_vio.h>
#include <hb_dnn.h>
#include <hb_ipc.h>
​
/* 项目模块头文件 */
#include "rdk3_cam.h"
#include "memory_manager.h"
#include "logger.h"
#include "event_loop.h"
#include "isp_tuning.h"
#include "ai_pipeline.h"
#include "ipc_bus.h"
#include "timeshift_cache.h"
​
/*=============================================================================
 * 全局变量
 *============================================================================*/
​
static volatile bool g_running = true;           ///< 运行标志
static rdk3_cam_config_t g_config;               ///< 系统配置
static event_loop_t* g_event_loop = NULL;        ///< 事件循环实例
static ai_pipeline_t* g_ai_pipeline = NULL;      ///< AI流水线实例
static timeshift_cache_t* g_timeshift_cache = NULL; ///< 时移缓存实例
static ipc_context_t* g_ipc_ctx = NULL;          ///< IPC上下文
​
/* RDK3 SDK句柄 */
static hb_sys_handle_t g_sys_handle = NULL;      ///< 系统句柄
static hb_vio_handle_t g_vio_handle = NULL;      ///< 视频输入输出句柄
static hb_dnn_handle_t g_dnn_handle = NULL;      ///< BPU推理句柄
​
/* 性能统计 */
static struct {
    uint64_t frame_count;           ///< 处理帧数
    uint64_t start_time_us;         ///< 开始时间
    float current_fps;              ///< 当前FPS
    float avg_fps;                  ///< 平均FPS
    uint32_t max_latency_us;        ///< 最大延迟
    uint32_t min_latency_us;        ///< 最小延迟
    uint32_t avg_latency_us;        ///< 平均延迟
} g_perf_stats;
​
/*=============================================================================
 * 信号处理
 *============================================================================*/
​
/**
 * @brief 信号处理函数
 * @param sig 信号编号
 * 
 * @note 支持优雅退出:SIGINT(Ctrl+C), SIGTERM
 */
static void signal_handler(int sig)
{
    LOG_INFO("Received signal %d, shutting down...", sig);
    g_running = false;
    
    /* 通知事件循环退出 */
    if (g_event_loop) {
        event_loop_stop(g_event_loop);
    }
}
​
/*=============================================================================
 * RDK3 SDK初始化
 *============================================================================*/
​
/**
 * @brief 初始化地平线RDK3 SDK
 * @return 成功返回0
 * 
 * @note 必须最先调用,初始化硬件资源
 * @warning 失败时系统无法继续运行
 */
static int rdk3_sdk_init(void)
{
    LOG_INFO("Initializing Horizon RDK3 SDK...");
    
    /* 1. 初始化系统 */
    hb_sys_config_t sys_config = {
        .log_level = HB_LOG_LEVEL_INFO,
        .mem_config = {
            .cma_size_mb = 512,      /* CMA内存512MB */
            .bpu_mem_size_mb = 256,   /* BPU内存256MB */
            .vio_mem_size_mb = 128    /* VIO内存128MB */
        }
    };
    
    int ret = hb_sys_init(&sys_config, &g_sys_handle);
    if (ret != 0) {
        LOG_ERROR("hb_sys_init failed: %d", ret);
        return -1;
    }
    LOG_INFO("System initialized, handle=%p", g_sys_handle);
    
    /* 2. 初始化视频输入输出 */
    hb_vio_config_t vio_config = {
        .sensor_type = HB_SENSOR_IMX415,
        .sensor_bus = HB_MIPI_CSI0,
        .width = g_config.video_width,
        .height = g_config.video_height,
        .framerate = g_config.video_framerate,
        .pixel_format = HB_PIXEL_FORMAT_NV12,
        .buffer_count = 4,           /* 4个缓冲区 */
        .enable_isp = true,          /* 使能ISP */
        .enable_3a = true            /* 使能3A */
    };
    
    ret = hb_vio_init(&vio_config, &g_vio_handle);
    if (ret != 0) {
        LOG_ERROR("hb_vio_init failed: %d", ret);
        return -2;
    }
    LOG_INFO("VIO initialized, sensor=IMX415, resolution=%dx%d@%dfps",
             g_config.video_width, g_config.video_height, g_config.video_framerate);
    
    /* 3. 初始化BPU(DNN) */
    hb_dnn_config_t dnn_config = {
        .model_path = g_config.detect_model_path,
        .core_id = HB_BPU_CORE_0,
        .priority = HB_TASK_PRIORITY_NORMAL,
        .timeout_ms = 100
    };
    
    ret = hb_dnn_init(&dnn_config, &g_dnn_handle);
    if (ret != 0) {
        LOG_ERROR("hb_dnn_init failed: %d", ret);
        return -3;
    }
    LOG_INFO("DNN/BPU initialized, model=%s", g_config.detect_model_path);
    
    /* 4. 启动视频流 */
    ret = hb_vio_start_stream(g_vio_handle);
    if (ret != 0) {
        LOG_ERROR("hb_vio_start_stream failed: %d", ret);
        return -4;
    }
    LOG_INFO("Video stream started");
    
    return 0;
}
​
/**
 * @brief 反初始化RDK3 SDK
 */
static void rdk3_sdk_deinit(void)
{
    LOG_INFO("Deinitializing RDK3 SDK...");
    
    if (g_vio_handle) {
        hb_vio_stop_stream(g_vio_handle);
        hb_vio_deinit(g_vio_handle);
        g_vio_handle = NULL;
    }
    
    if (g_dnn_handle) {
        hb_dnn_deinit(g_dnn_handle);
        g_dnn_handle = NULL;
    }
    
    if (g_sys_handle) {
        hb_sys_deinit(g_sys_handle);
        g_sys_handle = NULL;
    }
    
    LOG_INFO("RDK3 SDK deinitialized");
}
​
/*=============================================================================
 * 内存池配置
 *============================================================================*/
​
/**
 * @brief 内存池配置数组
 */
static const mem_pool_cfg_t g_mem_pools[] = {
    {
        .type = MEM_POOL_CMA,
        .name = "cma_video",
        .total_size = 512 * 1024 * 1024,  /* 512MB CMA */
        .flags = MEM_FLAG_CACHE_ALIGN
    },
    {
        .type = MEM_POOL_SLAB,
        .name = "slab_frame",
        .block_size = sizeof(frame_t),
        .block_count = 32,
        .flags = MEM_FLAG_ZERO_INIT
    },
    {
        .type = MEM_POOL_SLAB,
        .name = "slab_ai_tensor",
        .block_size = 4 * 1024 * 1024,    /* 4MB per tensor */
        .block_count = 8,
        .flags = MEM_FLAG_CACHE_ALIGN | MEM_FLAG_ZERO_INIT
    },
    {
        .type = MEM_POOL_SLAB,
        .name = "slab_detection",
        .block_size = 100 * sizeof(detection_object_t),
        .block_count = 4,
        .flags = MEM_FLAG_ZERO_INIT
    }
};
​
/*=============================================================================
 * 事件观察者(观察者模式)
 *============================================================================*/
​
/**
 * @brief 视频帧到达观察者
 */
static int frame_observer_on_event(observer_t* self, const event_t* event)
{
    (void)self;
    
    if (event->type != EVENT_NEW_FRAME) {
        return 0;
    }
    
    uint64_t start_us = get_time_us();
    
    /* 1. 获取帧数据 */
    frame_t* frame = (frame_t*)event->data.frame_event.frame_data;
    if (!frame) {
        return -1;
    }
    
    /* 2. 更新性能统计 */
    g_perf_stats.frame_count++;
    
    /* 3. 推送到时移缓存 */
    if (g_timeshift_cache) {
        timeshift_cache_push(g_timeshift_cache, frame);
    }
    
    /* 4. 提交AI任务(异步) */
    if (g_ai_pipeline && g_config.ai_enabled) {
        ai_pipeline_submit_async(g_ai_pipeline, frame, NULL, NULL);
    }
    
    /* 5. 更新ISP参数(基于AI结果) */
    static uint32_t frame_counter = 0;
    if (++frame_counter % 30 == 0) {
        /* 每30帧更新一次ISP参数 */
        isp_tuning_params_t params = isp_tuning_auto_adapt(0, 300.0f, 5500);
        isp_tuning_update_smooth(&params, 500);
    }
    
    uint64_t latency_us = get_time_us() - start_us;
    
    /* 更新延迟统计 */
    if (latency_us > g_perf_stats.max_latency_us) {
        g_perf_stats.max_latency_us = latency_us;
    }
    if (latency_us < g_perf_stats.min_latency_us || g_perf_stats.min_latency_us == 0) {
        g_perf_stats.min_latency_us = latency_us;
    }
    
    /* 滑动平均延迟 */
    g_perf_stats.avg_latency_us = 
        (g_perf_stats.avg_latency_us * 99 + latency_us) / 100;
    
    return 0;
}
​
/**
 * @brief ISP事件观察者
 */
static int isp_observer_on_event(observer_t* self, const event_t* event)
{
    (void)self;
    
    if (event->type != EVENT_ISP_3A_READY) {
        return 0;
    }
    
    /* 获取ISP统计信息 */
    uint32_t avg_luminance = event->data.isp_event.avg_luminance;
    uint16_t color_temp = event->data.isp_event.color_temp;
    
    /* 动态调整场景识别 */
    int scene_type = 0;  /* 0=室内, 1=室外, 2=夜景 */
    
    if (avg_luminance < 50) {
        scene_type = 2;  /* 夜景 */
    } else if (avg_luminance > 200) {
        scene_type = 1;  /* 室外 */
    } else {
        scene_type = 0;  /* 室内 */
    }
    
    /* 自适应ISP参数 */
    isp_tuning_params_t params = isp_tuning_auto_adapt(scene_type, 
                                                        avg_luminance, 
                                                        color_temp);
    isp_tuning_update_smooth(&params, 1000);
    
    return 0;
}
​
/**
 * @brief AI结果观察者
 */
static int ai_observer_on_event(observer_t* self, const event_t* event)
{
    (void)self;
    
    if (event->type != EVENT_AI_RESULT) {
        return 0;
    }
    
    detection_result_t* result = (detection_result_t*)event->data.ai_event.detections;
    
    if (result && result->object_count > 0) {
        LOG_DEBUG("AI detected %u objects, inference time=%uus",
                  result->object_count, result->inference_time_us);
        
        /* 根据检测结果调整ISP ROI */
        for (uint32_t i = 0; i < result->object_count && i < 3; i++) {
            detection_object_t* obj = &result->objects[i];
            
            /* 如果检测到人脸,设置ISP对焦ROI */
            if (obj->class_id == 0) {  /* 假设0是人脸类别 */
                /* 通过IPC发送ROI设置命令 */
                ipc_cmd_t cmd = {
                    .cmd_id = CMD_ISP_SET_FOCUS_ROI,
                    .args = {
                        (uint32_t)(obj->bbox.x1 * 1000),
                        (uint32_t)(obj->bbox.y1 * 1000),
                        (uint32_t)(obj->bbox.x2 * 1000),
                        (uint32_t)(obj->bbox.y2 * 1000)
                    },
                    .timeout_ms = 10
                };
                ipc_send_async(g_ipc_ctx, &cmd);
                break;
            }
        }
    }
    
    return 0;
}
​
/*=============================================================================
 * 性能监控线程
 *============================================================================*/
​
/**
 * @brief 性能监控线程函数
 * @param arg 线程参数
 * @return NULL
 * 
 * @note 每秒输出一次性能统计
 */
static void* perf_monitor_thread(void* arg)
{
    (void)arg;
    
    uint64_t last_frame_count = 0;
    uint64_t last_time_us = get_time_us();
    
    while (g_running) {
        sleep(5);  /* 每5秒输出一次 */
        
        uint64_t now_us = get_time_us();
        uint64_t elapsed_us = now_us - last_time_us;
        uint64_t frame_diff = g_perf_stats.frame_count - last_frame_count;
        
        if (elapsed_us > 0) {
            g_perf_stats.current_fps = frame_diff * 1000000.0f / elapsed_us;
        }
        
        /* 计算平均FPS */
        uint64_t total_elapsed_us = now_us - g_perf_stats.start_time_us;
        if (total_elapsed_us > 0) {
            g_perf_stats.avg_fps = g_perf_stats.frame_count * 1000000.0f / total_elapsed_us;
        }
        
        LOG_INFO("[PERF] FPS: curr=%.1f avg=%.1f | Latency: avg=%uus min=%uus max=%uus | Frames=%llu",
                 g_perf_stats.current_fps,
                 g_perf_stats.avg_fps,
                 g_perf_stats.avg_latency_us,
                 g_perf_stats.min_latency_us,
                 g_perf_stats.max_latency_us,
                 (unsigned long long)g_perf_stats.frame_count);
        
        /* 打印内存统计 */
        memory_manager_dump_stats();
        
        /* 打印时移缓存统计 */
        if (g_timeshift_cache) {
            timeshift_cache_stat_t ts_stat;
            timeshift_cache_get_stat(g_timeshift_cache, &ts_stat);
            LOG_INFO("[TIMESHIFT] total_frames=%llu, cached=%u, replay_count=%u",
                     (unsigned long long)ts_stat.total_pushed,
                     ts_stat.current_size,
                     ts_stat.replay_count);
        }
        
        last_frame_count = g_perf_stats.frame_count;
        last_time_us = now_us;
    }
    
    return NULL;
}
​
/*=============================================================================
 * 时移回放演示
 *============================================================================*/
​
/**
 * @brief 时移回放演示线程
 * @param arg 线程参数
 * @return NULL
 * 
 * @note 演示从时移缓存中回放10秒前的视频
 */
static void* timeshift_replay_demo(void* arg)
{
    (void)arg;
    
    /* 等待系统稳定 */
    sleep(30);
    
    LOG_INFO("Starting timeshift replay demo...");
    
    while (g_running) {
        /* 每60秒回放一次10秒前的视频 */
        sleep(60);
        
        LOG_INFO("Replaying video from 10 seconds ago...");
        
        /* 设置回放时间偏移(-10秒) */
        int64_t offset_us = -10 * 1000000LL;
        timeshift_cache_set_replay_offset(g_timeshift_cache, offset_us);
        
        /* 回放5秒钟 */
        uint64_t replay_start_us = get_time_us();
        uint32_t replay_frames = 0;
        
        while ((get_time_us() - replay_start_us) < 5 * 1000000LL) {
            frame_t* frame = timeshift_cache_get_next(g_timeshift_cache);
            if (frame) {
                replay_frames++;
                /* 这里可以将frame送去编码或显示 */
                LOG_TRACE("Replay frame %u", frame->sequence);
                timeshift_cache_release_frame(g_timeshift_cache, frame);
            } else {
                usleep(10000);  /* 等待新帧 */
            }
        }
        
        LOG_INFO("Replay completed: %u frames in 5 seconds", replay_frames);
        
        /* 恢复正常实时模式 */
        timeshift_cache_set_replay_offset(g_timeshift_cache, 0);
    }
    
    return NULL;
}
​
/*=============================================================================
 * 配置加载
 *============================================================================*/
​
/**
 * @brief 加载配置文件
 * @param config_path 配置文件路径
 * @return 成功返回0
 * 
 * @note 支持YAML/JSON格式(简化实现)
 */
static int load_config(const char* config_path, rdk3_cam_config_t* config)
{
    /* 设置默认配置 */
    memset(config, 0, sizeof(rdk3_cam_config_t));
    
    config->video_width = 1920;
    config->video_height = 1080;
    config->video_framerate = 30;
    config->video_format = HB_PIXEL_FORMAT_NV12;
    
    config->ai_enabled = true;
    config->detect_model_path = "/data/models/yolov5s.hbm";
    config->ai_confidence_threshold = 0.5f;
    config->ai_nms_threshold = 0.45f;
    
    config->log_level = LOG_LEVEL_INFO;
    config->log_output = LOG_OUTPUT_CONSOLE | LOG_OUTPUT_FILE;
    config->log_file_path = "/var/log/rdk3_cam.log";
    
    config->cma_pool_size = 512;
    config->dma_pool_size = 256;
    config->ai_tensor_pool_size = 128;
    
    config->frame_cache_size = 300;      /* 缓存300帧(10秒@30fps) */
    config->model_cache_size = 3;
    
    /* 如果提供了配置文件,解析之(简化) */
    if (config_path && access(config_path, F_OK) == 0) {
        LOG_INFO("Loading config from %s", config_path);
        /* 实际应用中使用yaml解析库 */
    }
    
    return 0;
}
​
/*=============================================================================
 * 主函数
 *============================================================================*/
​
/**
 * @brief 打印使用帮助
 */
static void print_usage(const char* progname)
{
    printf("Usage: %s [options]\n", progname);
    printf("Options:\n");
    printf("  -c, --config FILE    Config file path\n");
    printf("  -d, --daemon         Run as daemon\n");
    printf("  -l, --level LEVEL    Log level (0-5)\n");
    printf("  -h, --help           Show this help\n");
    printf("\nExample:\n");
    printf("  %s -c /etc/rdk3_cam.yaml\n", progname);
}
​
/**
 * @brief 主函数入口
 */
int main(int argc, char* argv[])
{
    int ret = 0;
    pthread_t perf_thread;
    pthread_t replay_thread;
    
    /*=========================================================================
     * 1. 解析命令行参数
     *========================================================================*/
    const char* config_path = NULL;
    bool run_as_daemon = false;
    
    static struct option long_options[] = {
        {"config", required_argument, 0, 'c'},
        {"daemon", no_argument, 0, 'd'},
        {"level", required_argument, 0, 'l'},
        {"help", no_argument, 0, 'h'},
        {0, 0, 0, 0}
    };
    
    int opt;
    while ((opt = getopt_long(argc, argv, "c:dl:h", long_options, NULL)) != -1) {
        switch (opt) {
            case 'c':
                config_path = optarg;
                break;
            case 'd':
                run_as_daemon = true;
                break;
            case 'l':
                /* 日志级别稍后设置 */
                break;
            case 'h':
            default:
                print_usage(argv[0]);
                return 0;
        }
    }
    
    /* 守护进程模式 */
    if (run_as_daemon) {
        if (daemon(1, 0) != 0) {
            perror("daemon");
            return 1;
        }
    }
    
    /*=========================================================================
     * 2. 加载配置
     *========================================================================*/
    ret = load_config(config_path, &g_config);
    if (ret != 0) {
        fprintf(stderr, "Failed to load config\n");
        return 1;
    }
    
    /*=========================================================================
     * 3. 初始化日志系统
     *========================================================================*/
    logger_config_t log_config = {
        .level = g_config.log_level,
        .output = g_config.log_output,
        .file_path = g_config.log_file_path,
        .file_max_size = 10 * 1024 * 1024,
        .file_max_count = 3,
        .ringbuf_size = 1024 * 1024,
        .enable_timestamp = true,
        .enable_thread_id = true,
        .enable_file_line = true,
        .async_mode = true,
        .async_queue_size = 4096
    };
    
    logger_init(&log_config);
    
    LOG_INFO("========================================");
    LOG_INFO("RDK3 AI Camera v1.0.0 Starting...");
    LOG_INFO("========================================");
    
    /*=========================================================================
     * 4. 设置信号处理
     *========================================================================*/
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);
    signal(SIGPIPE, SIG_IGN);
    
    /*=========================================================================
     * 5. 初始化内存管理(对象池模式)
     *========================================================================*/
    LOG_INFO("Initializing memory manager...");
    ret = memory_manager_init(g_mem_pools, sizeof(g_mem_pools) / sizeof(g_mem_pools[0]));
    if (ret != 0) {
        LOG_FATAL("Memory manager init failed: %d", ret);
        goto error_exit;
    }
    
    /*=========================================================================
     * 6. 初始化RDK3 SDK(BPU硬件加速)
     *========================================================================*/
    ret = rdk3_sdk_init();
    if (ret != 0) {
        LOG_FATAL("RDK3 SDK init failed: %d", ret);
        goto error_exit;
    }
    
    /*=========================================================================
     * 7. 初始化双架构IPC
     *========================================================================*/
    LOG_INFO("Initializing IPC bus (ARM <-> ARM-None)...");
    g_ipc_ctx = ipc_bus_init("/dev/shm/rdk3_ipc", 2 * 1024 * 1024, true);
    if (!g_ipc_ctx) {
        LOG_WARN("IPC bus init failed, running in single-core mode");
    } else {
        LOG_INFO("IPC bus initialized");
    }
    
    /*=========================================================================
     * 8. 初始化ISP调优
     *========================================================================*/
    LOG_INFO("Initializing ISP tuning...");
    ret = isp_tuning_init("/etc/isp/imx415_tuning.bin");
    if (ret != 0) {
        LOG_WARN("ISP tuning init failed, using defaults");
    }
    
    /*=========================================================================
     * 9. 初始化事件循环(观察者模式)
     *========================================================================*/
    LOG_INFO("Initializing event loop...");
    event_loop_config_t el_config = {
        .max_events = 64,
        .event_queue_size = 1024,
        .epoll_timeout_ms = 100,
        .enable_priority_queue = true,
        .enable_stats = true
    };
    
    g_event_loop = event_loop_get_instance(&el_config);
    if (!g_event_loop) {
        LOG_FATAL("Event loop init failed");
        goto error_exit;
    }
    
    /* 注册观察者 */
    static observer_t frame_observer = {
        .name = "FrameObserver",
        .on_event = frame_observer_on_event,
        .subscribed_events = EVENT_NEW_FRAME,
        .priority = EVENT_PRIO_CRITICAL
    };
    event_loop_register_observer(g_event_loop, &frame_observer);
    
    static observer_t isp_observer = {
        .name = "ISPObserver",
        .on_event = isp_observer_on_event,
        .subscribed_events = EVENT_ISP_3A_READY,
        .priority = EVENT_PRIO_HIGH
    };
    event_loop_register_observer(g_event_loop, &isp_observer);
    
    static observer_t ai_observer = {
        .name = "AIObserver",
        .on_event = ai_observer_on_event,
        .subscribed_events = EVENT_AI_RESULT,
        .priority = EVENT_PRIO_NORMAL
    };
    event_loop_register_observer(g_event_loop, &ai_observer);
    
    /*=========================================================================
     * 10. 初始化AI流水线(责任链模式)
     *========================================================================*/
    LOG_INFO("Initializing AI pipeline...");
    
    ai_pipeline_config_t ai_config = {
        .detect_model_path = g_config.detect_model_path,
        .preprocess = {
            .target_width = 640,
            .target_height = 640,
            .target_format = TENSOR_FORMAT_RGB,
            .keep_aspect_ratio = true,
            .pad_value = 114,
            .mean = {0.485f, 0.456f, 0.406f},
            .std = {0.229f, 0.224f, 0.225f},
            .convert_to_rgb = true
        },
        .postprocess = {
            .confidence_threshold = g_config.ai_confidence_threshold,
            .nms_threshold = g_config.ai_nms_threshold,
            .max_detections = 100,
            .enable_feature_extract = false
        },
        .yolo = {
            .num_classes = 80,
            .num_anchors = 3,
            .anchors = {{10,13}, {16,30}, {33,23}},
            .stride = {8, 16, 32},
            .input_width = 640,
            .input_height = 640
        },
        .tracker = {
            .max_tracked_objects = 50,
            .max_lost_frames = 30,
            .iou_threshold = 0.3f,
            .feature_threshold = 0.5f,
            .use_kalman = true
        },
        .max_pending_tasks = 8,
        .enable_async = true,
        .worker_threads = 2
    };
    
    g_ai_pipeline = ai_pipeline_create(&ai_config);
    if (!g_ai_pipeline) {
        LOG_FATAL("AI pipeline init failed");
        goto error_exit;
    }
    LOG_INFO("AI pipeline initialized");
    
    /*=========================================================================
     * 11. 初始化时移缓存
     *========================================================================*/
    LOG_INFO("Initializing timeshift cache (capacity=%u frames)...", 
             g_config.frame_cache_size);
    
    timeshift_cache_config_t ts_config = {
        .capacity = g_config.frame_cache_size,
        .max_frame_size = g_config.video_width * g_config.video_height * 1.5f,
        .recycle_threshold = 0.8f,
        .enable_compression = false
    };
    
    g_timeshift_cache = timeshift_cache_create(&ts_config);
    if (!g_timeshift_cache) {
        LOG_WARN("Timeshift cache init failed, continuing without caching");
    }
    
    /*=========================================================================
     * 12. 注册V4L2设备到事件循环
     *========================================================================*/
    /* 获取V4L2设备文件描述符(从VIO模块) */
    int v4l2_fd = hb_vio_get_fd(g_vio_handle);
    if (v4l2_fd >= 0) {
        event_loop_add_fd(g_event_loop, v4l2_fd, EPOLLIN,
                          /* 帧到达回调 */ NULL, NULL);
        LOG_INFO("V4L2 device registered to event loop");
    }
    
    /*=========================================================================
     * 13. 启动性能监控线程
     *========================================================================*/
    g_perf_stats.start_time_us = get_time_us();
    pthread_create(&perf_thread, NULL, perf_monitor_thread, NULL);
    
    /*=========================================================================
     * 14. 启动时移回放演示线程(可选)
     *========================================================================*/
    pthread_create(&replay_thread, NULL, timeshift_replay_demo, NULL);
    
    /*=========================================================================
     * 15. 启动事件循环(主线程阻塞)
     *========================================================================*/
    LOG_INFO("========================================");
    LOG_INFO("RDK3 AI Camera is RUNNING");
    LOG_INFO("========================================");
    LOG_INFO("Resolution: %dx%d@%dfps", 
             g_config.video_width, g_config.video_height, g_config.video_framerate);
    LOG_INFO("AI Model: %s", g_config.detect_model_path);
    LOG_INFO("Press Ctrl+C to stop");
    
    ret = event_loop_start(g_event_loop);
    
    /*=========================================================================
     * 16. 等待退出
     *========================================================================*/
    LOG_INFO("Event loop exited, cleaning up...");
    
    pthread_join(perf_thread, NULL);
    pthread_join(replay_thread, NULL);
    
error_exit:
    /*=========================================================================
     * 17. 清理资源(逆序)
     *========================================================================*/
    LOG_INFO("Cleaning up resources...");
    
    /* 停止AI流水线 */
    if (g_ai_pipeline) {
        ai_pipeline_destroy(g_ai_pipeline);
        g_ai_pipeline = NULL;
    }
    
    /* 销毁时移缓存 */
    if (g_timeshift_cache) {
        timeshift_cache_destroy(g_timeshift_cache);
        g_timeshift_cache = NULL;
    }
    
    /* 反初始化IPC */
    if (g_ipc_ctx) {
        ipc_bus_deinit(g_ipc_ctx);
        g_ipc_ctx = NULL;
    }
    
    /* 反初始化RDK3 SDK */
    rdk3_sdk_deinit();
    
    /* 反初始化日志 */
    LOG_INFO("RDK3 AI Camera stopped");
    logger_deinit();
    
    LOG_INFO("Cleanup completed, exiting.");
    
    return ret;
}

时移缓存模块 timeshift_cache.h

/**
 * @file timeshift_cache.h
 * @brief 时移缓存模块(环形缓冲区)
 * @author System Team
 * 
 * @section 功能说明
 * - 实现视频帧的环形缓存,支持时移回放
 * - 支持实时写入和时移读取两种模式
 * - 自动回收旧帧,避免内存溢出
 * 
 * @section 设计模式
 * - **环形缓冲区(Ring Buffer)**: 固定大小循环存储
 * - **读写锁(Read-Write Lock)**: 支持并发读写
 */
​
#ifndef TIMESHIFT_CACHE_H
#define TIMESHIFT_CACHE_H
​
#include <stdint.h>
#include <stdbool.h>
#include <pthread.h>
​
#ifdef __cplusplus
extern "C" {
#endif
​
/* 前向声明 */
typedef struct timeshift_cache timeshift_cache_t;
​
/*=============================================================================
 * 配置结构体
 *============================================================================*/
​
/**
 * @brief 时移缓存配置
 */
typedef struct {
    uint32_t capacity;              ///< 最大缓存帧数(默认300=10秒@30fps)
    size_t max_frame_size;          ///< 单帧最大大小(字节)
    float recycle_threshold;        ///< 回收阈值(0-1, 超过容量*阈值开始回收)
    bool enable_compression;        ///< 是否启用压缩(暂不支持)
} timeshift_cache_config_t;
​
/**
 * @brief 时移缓存统计信息
 */
typedef struct {
    uint64_t total_pushed;          ///< 总推入帧数
    uint64_t total_popped;          ///< 总弹出帧数
    uint32_t current_size;          ///< 当前缓存帧数
    uint32_t max_size;              ///< 最大缓存帧数
    uint32_t replay_count;          ///< 回放次数
    uint32_t lost_frames;           ///< 丢失帧数(缓存满)
} timeshift_cache_stat_t;
​
/*=============================================================================
 * API函数
 *============================================================================*/
​
/**
 * @brief 创建时移缓存
 * @param config 缓存配置
 * @return 缓存句柄
 */
timeshift_cache_t* timeshift_cache_create(const timeshift_cache_config_t* config);
​
/**
 * @brief 销毁时移缓存
 * @param cache 缓存句柄
 */
void timeshift_cache_destroy(timeshift_cache_t* cache);
​
/**
 * @brief 推入帧到缓存(实时模式)
 * @param cache 缓存句柄
 * @param frame 帧数据(会被拷贝)
 * @return 成功返回0
 * 
 * @note 帧数据会被深拷贝到内部缓冲区
 */
int timeshift_cache_push(timeshift_cache_t* cache, const frame_t* frame);
​
/**
 * @brief 设置回放偏移
 * @param cache 缓存句柄
 * @param offset_us 偏移时间(微秒, 负数表示过去)
 * @return 成功返回0
 * 
 * @note offset_us = -10000000 表示回放10秒前的视频
 */
int timeshift_cache_set_replay_offset(timeshift_cache_t* cache, int64_t offset_us);
​
/**
 * @brief 获取下一帧(回放模式)
 * @param cache 缓存句柄
 * @return 帧指针(需要调用release释放)
 * 
 * @note 调用后必须使用timeshift_cache_release_frame释放
 */
frame_t* timeshift_cache_get_next(timeshift_cache_t* cache);
​
/**
 * @brief 释放帧
 * @param cache 缓存句柄
 * @param frame 帧指针
 */
void timeshift_cache_release_frame(timeshift_cache_t* cache, frame_t* frame);
​
/**
 * @brief 获取缓存统计信息
 * @param cache 缓存句柄
 * @param stat 输出统计信息
 */
void timeshift_cache_get_stat(timeshift_cache_t* cache, timeshift_cache_stat_t* stat);
​
#ifdef __cplusplus
}
#endif
​
#endif /* TIMESHIFT_CACHE_H */

时移缓存实现 timeshift_cache.c

/**
 * @file timeshift_cache.c
 * @brief 时移缓存实现
 */
​
#include "timeshift_cache.h"
#include "memory_manager.h"
#include "logger.h"
#include <stdlib.h>
#include <string.h>
​
/*=============================================================================
 * 缓存节点
 *============================================================================*/
​
/**
 * @brief 缓存节点
 */
typedef struct cache_node {
    frame_t* frame;                 ///< 帧数据
    uint64_t timestamp_us;          ///< 时间戳
    uint32_t sequence;              ///< 帧序号
    bool in_use;                    ///< 是否在使用中
    struct cache_node* next;        ///< 下一个节点
} cache_node_t;
​
/**
 * @brief 时移缓存上下文
 */
struct timeshift_cache {
    /* 环形缓冲区 */
    cache_node_t* nodes;            ///< 节点数组
    uint32_t capacity;              ///< 容量
    uint32_t head;                  ///< 写指针
    uint32_t tail;                  ///< 读指针(实时模式)
    uint32_t size;                  ///< 当前大小
    
    /* 回放模式 */
    bool replay_mode;               ///< 是否处于回放模式
    int64_t replay_offset_us;       ///< 回放偏移(微秒)
    uint32_t replay_pos;            ///< 回放读取位置
    uint32_t replay_target_seq;     ///< 目标帧序号
    
    /* 配置 */
    timeshift_cache_config_t config;
    
    /* 统计 */
    timeshift_cache_stat_t stats;
    
    /* 锁 */
    pthread_rwlock_t rwlock;
};
​
/*=============================================================================
 * 实现函数
 *============================================================================*/
​
timeshift_cache_t* timeshift_cache_create(const timeshift_cache_config_t* config)
{
    if (!config || config->capacity == 0) {
        return NULL;
    }
    
    timeshift_cache_t* cache = (timeshift_cache_t*)calloc(1, sizeof(timeshift_cache_t));
    if (!cache) {
        return NULL;
    }
    
    memcpy(&cache->config, config, sizeof(timeshift_cache_config_t));
    cache->capacity = config->capacity;
    
    /* 分配节点数组 */
    cache->nodes = (cache_node_t*)calloc(cache->capacity, sizeof(cache_node_t));
    if (!cache->nodes) {
        free(cache);
        return NULL;
    }
    
    /* 预分配帧内存(从内存池) */
    for (uint32_t i = 0; i < cache->capacity; i++) {
        cache->nodes[i].frame = (frame_t*)memory_pool_alloc("slab_frame", sizeof(frame_t));
        if (cache->nodes[i].frame) {
            /* 分配帧数据缓冲区 */
            cache->nodes[i].frame->data[0] = memory_pool_alloc("cma_video", 
                                                                cache->config.max_frame_size);
        }
    }
    
    pthread_rwlock_init(&cache->rwlock, NULL);
    
    LOG_INFO("Timeshift cache created: capacity=%u, max_frame_size=%zu",
             cache->capacity, cache->config.max_frame_size);
    
    return cache;
}
​
void timeshift_cache_destroy(timeshift_cache_t* cache)
{
    if (!cache) return;
    
    pthread_rwlock_wrlock(&cache->rwlock);
    
    /* 释放帧内存 */
    for (uint32_t i = 0; i < cache->capacity; i++) {
        if (cache->nodes[i].frame) {
            if (cache->nodes[i].frame->data[0]) {
                memory_pool_free("cma_video", cache->nodes[i].frame->data[0]);
            }
            memory_pool_free("slab_frame", cache->nodes[i].frame);
        }
    }
    
    free(cache->nodes);
    
    pthread_rwlock_unlock(&cache->rwlock);
    pthread_rwlock_destroy(&cache->rwlock);
    
    free(cache);
    
    LOG_INFO("Timeshift cache destroyed");
}
​
int timeshift_cache_push(timeshift_cache_t* cache, const frame_t* frame)
{
    if (!cache || !frame) return -1;
    
    pthread_rwlock_wrlock(&cache->rwlock);
    
    /* 如果在回放模式,不接受新帧 */
    if (cache->replay_mode) {
        pthread_rwlock_unlock(&cache->rwlock);
        return -2;
    }
    
    /* 获取当前写入位置 */
    cache_node_t* node = &cache->nodes[cache->head];
    
    /* 拷贝帧数据 */
    memcpy(node->frame, frame, sizeof(frame_t));
    
    /* 深拷贝图像数据(从内存池分配) */
    if (frame->data[0] && node->frame->data[0]) {
        memcpy(node->frame->data[0], frame->data[0], frame->size);
    }
    
    node->timestamp_us = frame->timestamp;
    node->sequence = frame->sequence;
    node->in_use = false;
    
    /* 更新写指针 */
    cache->head = (cache->head + 1) % cache->capacity;
    
    /* 更新大小 */
    if (cache->size < cache->capacity) {
        cache->size++;
    } else {
        /* 缓存满,覆盖最旧的帧 */
        cache->tail = (cache->tail + 1) % cache->capacity;
        cache->stats.lost_frames++;
    }
    
    cache->stats.total_pushed++;
    
    pthread_rwlock_unlock(&cache->rwlock);
    
    return 0;
}
​
int timeshift_cache_set_replay_offset(timeshift_cache_t* cache, int64_t offset_us)
{
    if (!cache) return -1;
    
    pthread_rwlock_wrlock(&cache->rwlock);
    
    if (offset_us == 0) {
        /* 退出回放模式 */
        cache->replay_mode = false;
        cache->replay_offset_us = 0;
        LOG_INFO("Timeshift replay disabled, returning to live mode");
    } else {
        /* 进入回放模式 */
        uint64_t now_us = get_time_us();
        uint64_t target_time_us = now_us + offset_us;
        
        /* 查找目标帧(二分查找) */
        cache->replay_pos = cache->tail;
        cache->replay_target_seq = 0;
        cache->replay_mode = true;
        cache->replay_offset_us = offset_us;
        cache->stats.replay_count++;
        
        LOG_INFO("Timeshift replay enabled: offset=%lldms", 
                 (long long)(-offset_us / 1000));
    }
    
    pthread_rwlock_unlock(&cache->rwlock);
    
    return 0;
}
​
frame_t* timeshift_cache_get_next(timeshift_cache_t* cache)
{
    if (!cache) return NULL;
    
    pthread_rwlock_rdlock(&cache->rwlock);
    
    if (!cache->replay_mode || cache->size == 0) {
        pthread_rwlock_unlock(&cache->rwlock);
        return NULL;
    }
    
    /* 获取当前回放位置的帧 */
    cache_node_t* node = &cache->nodes[cache->replay_pos];
    
    if (!node->frame || node->frame->sequence == 0) {
        pthread_rwlock_unlock(&cache->rwlock);
        return NULL;
    }
    
    /* 标记为使用中 */
    node->in_use = true;
    
    /* 移动到下一帧 */
    cache->replay_pos = (cache->replay_pos + 1) % cache->capacity;
    
    /* 如果已经追赶上实时流,退出回放模式 */
    if (cache->replay_pos == cache->head) {
        cache->replay_mode = false;
        LOG_INFO("Timeshift replay finished, caught up to live stream");
    }
    
    pthread_rwlock_unlock(&cache->rwlock);
    
    return node->frame;
}
​
void timeshift_cache_release_frame(timeshift_cache_t* cache, frame_t* frame)
{
    if (!cache || !frame) return;
    
    pthread_rwlock_wrlock(&cache->rwlock);
    
    /* 查找并释放帧 */
    for (uint32_t i = 0; i < cache->capacity; i++) {
        if (cache->nodes[i].frame == frame) {
            cache->nodes[i].in_use = false;
            break;
        }
    }
    
    pthread_rwlock_unlock(&cache->rwlock);
}
​
void timeshift_cache_get_stat(timeshift_cache_t* cache, timeshift_cache_stat_t* stat)
{
    if (!cache || !stat) return;
    
    pthread_rwlock_rdlock(&cache->rwlock);
    
    memcpy(stat, &cache->stats, sizeof(timeshift_cache_stat_t));
    stat->current_size = cache->size;
    stat->max_size = cache->capacity;
    
    pthread_rwlock_unlock(&cache->rwlock);
}

CMake构建文件 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(rdk3_cam_solution VERSION 1.0.0 LANGUAGES C)
​
#=============================================================================
# 编译选项
#=============================================================================
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -O2 -g -pthread")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG -O0")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG -O3")
​
#=============================================================================
# 查找依赖
#=============================================================================
# 地平线RDK3 SDK
find_path(HB_SDK_INCLUDE_DIR hb_common.h PATHS /usr/include/horizon)
find_library(HB_SDK_LIBRARY hb_sdk PATHS /usr/lib/horizon)
​
# 其他依赖
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBYAML REQUIRED yaml-0.1)
​
#=============================================================================
# 头文件路径
#=============================================================================
include_directories(
    ${CMAKE_CURRENT_SOURCE_DIR}/include
    ${HB_SDK_INCLUDE_DIR}
    ${LIBYAML_INCLUDE_DIRS}
)
​
#=============================================================================
# 源文件列表
#=============================================================================
set(SOURCES
    src/main.c
    src/core/memory/memory_manager.c
    src/core/log/logger.c
    src/core/ipc/ipc_bus.c
    src/middleware/isp/isp_tuning.c
    src/middleware/isp/isp_3a.c
    src/middleware/bpu/bpu_runtime.c
    src/algorithm/ai/ai_pipeline.c
    src/algorithm/ai/preprocess.c
    src/algorithm/ai/postprocess.c
    src/algorithm/ai/tracker.c
    src/algorithm/calib/calibrator.c
    src/application/event_loop.c
    src/application/timeshift_cache.c
)
​
#=============================================================================
# 可执行文件
#=============================================================================
add_executable(rdk3_cam ${SOURCES})
​
target_link_libraries(rdk3_cam
    ${HB_SDK_LIBRARY}
    ${LIBYAML_LIBRARIES}
    pthread
    m
    rt
    z
)
​
#=============================================================================
# 安装
#=============================================================================
install(TARGETS rdk3_cam DESTINATION bin)
install(FILES config/product_cam.yaml DESTINATION etc)
install(FILES scripts/start.sh DESTINATION bin)
​
#=============================================================================
# 测试
#=============================================================================
enable_testing()
add_subdirectory(tests)

启动脚本 scripts/start.sh

#!/bin/bash
#=============================================================================
# RDK3 AI Camera 启动脚本
#=============================================================================
​
set -e
​
APP_NAME="rdk3_cam"
APP_PATH="/usr/bin/${APP_NAME}"
CONFIG_PATH="/etc/rdk3_cam.yaml"
LOG_PATH="/var/log/rdk3_cam"
PID_FILE="/var/run/rdk3_cam.pid"
​
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
​
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}
​
log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}
​
log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}
​
# 检查是否已运行
check_running() {
    if [ -f "$PID_FILE" ]; then
        local pid=$(cat "$PID_FILE")
        if kill -0 "$pid" 2>/dev/null; then
            return 0
        else
            rm -f "$PID_FILE"
        fi
    fi
    return 1
}
​
# 启动服务
start() {
    if check_running; then
        log_warn "Service already running (PID: $(cat $PID_FILE))"
        return 1
    fi
    
    log_info "Starting $APP_NAME..."
    
    # 创建日志目录
    mkdir -p "$LOG_PATH"
    
    # 设置核心转储
    ulimit -c unlimited
    
    # 启动进程
    $APP_PATH -c "$CONFIG_PATH" >> "${LOG_PATH}/output.log" 2>&1 &
    local pid=$!
    echo $pid > "$PID_FILE"
    
    sleep 2
    
    if kill -0 "$pid" 2>/dev/null; then
        log_info "Service started successfully (PID: $pid)"
    else
        log_error "Service failed to start"
        rm -f "$PID_FILE"
        return 1
    fi
}
​
# 停止服务
stop() {
    if ! check_running; then
        log_warn "Service not running"
        return 1
    fi
    
    local pid=$(cat "$PID_FILE")
    log_info "Stopping $APP_NAME (PID: $pid)..."
    
    kill -TERM "$pid"
    
    # 等待进程退出
    local count=0
    while kill -0 "$pid" 2>/dev/null && [ $count -lt 30 ]; do
        sleep 1
        count=$((count + 1))
    done
    
    if kill -0 "$pid" 2>/dev/null; then
        log_warn "Force killing..."
        kill -9 "$pid"
    fi
    
    rm -f "$PID_FILE"
    log_info "Service stopped"
}
​
# 重启服务
restart() {
    stop
    sleep 2
    start
}
​
# 查看状态
status() {
    if check_running; then
        local pid=$(cat "$PID_FILE")
        log_info "Service is running (PID: $pid)"
        
        # 显示进程信息
        ps -p "$pid" -o pid,ppid,cmd,%cpu,%mem,etime
    else
        log_warn "Service is not running"
    fi
}
​
# 查看日志
logs() {
    tail -f "${LOG_PATH}/output.log"
}
​
# 性能监控
perf() {
    if ! check_running; then
        log_error "Service not running"
        return 1
    fi
    
    local pid=$(cat "$PID_FILE")
    
    echo "=== RDK3 Camera Performance ==="
    echo "PID: $pid"
    echo ""
    
    # CPU/内存使用
    ps -p "$pid" -o %cpu,%mem,vsz,rss
    
    echo ""
    echo "=== Thread Info ==="
    ps -T -p "$pid" -o pid,tid,comm,%cpu
    
    echo ""
    echo "=== Memory Map ==="
    cat "/proc/$pid/smaps" | grep -E "^(Size|Rss|Pss|Shared)" | head -20
}
​
# 主入口
case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        restart
        ;;
    status)
        status
        ;;
    logs)
        logs
        ;;
    perf)
        perf
        ;;
    *)
        echo "Usage: $0 {start|stop|restart|status|logs|perf}"
        exit 1
        ;;
esac
​
exit 0

配置文件 config/product_cam.yaml

#=============================================================================
# RDK3 AI Camera 产品配置文件
#=============================================================================
​
# 视频配置
video:
  width: 1920
  height: 1080
  framerate: 30
  format: "NV12"           # NV12, RGB888, RAW10
  sensor: "IMX415"
  mipi_lanes: 4
​
# AI配置
ai:
  enabled: true
  detect_model: "/data/models/yolov5s.hbm"
  classify_model: "/data/models/resnet18.hbm"
  track_model: "/data/models/reid.hbm"
  
  # 检测参数
  confidence_threshold: 0.5
  nms_threshold: 0.45
  max_detections: 100
  
  # 跟踪参数
  tracking:
    enabled: true
    max_tracked_objects: 50
    max_lost_frames: 30
    iou_threshold: 0.3
​
# ISP调优配置
isp:
  tuning_file: "/etc/isp/imx415_tuning.bin"
  
  # 3A配置
  ae:
    target_luminance: 60
    min_luminance: 30
    max_luminance: 200
    pid_kp: 0.5
    pid_ki: 0.1
    pid_kd: 0.05
  
  awb:
    mode: "greyworld"      # greyworld, perfect_reflect
    max_gain: 3.0
  
  af:
    mode: "hill_climbing"  # hill_climbing, contrast
    lens_min: 10
    lens_max: 1023
    coarse_step: 50
    fine_step: 5
    focus_threshold: 100
​
# 时移缓存配置
timeshift:
  enabled: true
  capacity_seconds: 10     # 缓存10秒
  recycle_threshold: 0.8   # 80%时开始回收
​
# 日志配置
logging:
  level: 3                 # 0=FATAL,1=ERROR,2=WARN,3=INFO,4=DEBUG,5=TRACE
  output: 3                # bit0=console, bit1=file
  file: "/var/log/rdk3_cam.log"
  max_size_mb: 10
  max_files: 3
​
# 网络配置
network:
  rtsp:
    enabled: true
    port: 554
    mount_point: "/live"
  
  websocket:
    enabled: true
    port: 8080
  
  mqtt:
    enabled: false
    broker: "mqtt://localhost:1883"
    topic: "rdk3/cam/events"
​
# 系统配置
system:
  cma_pool_mb: 512
  dma_pool_mb: 256
  ai_tensor_pool_mb: 128
  max_cpu_temp: 85        # 摄氏度
  enable_health_check: true

总结

模块 文件 功能
主程序 main.c 模块集成、生命周期管理、信号处理
内存管理 memory_manager.h/c CMA池、SLAB对象池、内存统计
日志系统 logger.h/c 异步日志、多输出目标、日志轮转
事件循环 event_loop.h/c 观察者模式、Reactor模式、优先级队列
IPC通信 ipc_bus.h/c 双架构通信、无锁队列、共享内存
ISP调优 isp_tuning.h/c 场景自适应、参数平滑、3A算法
AI流水线 ai_pipeline.h/c 责任链模式、BPU推理、目标跟踪
时移缓存 timeshift_cache.h/c 环形缓存、时移回放
构建文件 CMakeLists.txt 编译配置、依赖管理
启动脚本 start.sh 服务管理、性能监控
配置文件 product_cam.yaml 产品参数配置

产品特性

  1. 完整的生命周期管理 - 从初始化到优雅退出

  2. BPU硬件加速 - 地平线RDK3 SDK集成

  3. 双架构共存 - ARM Linux + ARM-None裸机通信

  4. 智能ISP调优 - 策略模式场景自适应

  5. AI推理流水线 - 责任链模式处理

  6. 时移回放 - 环形缓存支持10秒回放

  7. 观察者事件驱动 - 松耦合模块通信

  8. 内存池管理 - 零碎片高效分配

  9. 异步日志系统 - 高性能日志记录

测试建议

运行测试:

# 编译
mkdir build && cd build
cmake .. && make -j4
​
# 启动服务
./rdk3_cam -c ../config/product_cam.yaml
​
# 或使用脚本
sudo ./scripts/start.sh start
​
# 查看状态
./scripts/start.sh status
​
# 查看日志
./scripts/start.sh logs
​
# 停止服务
./scripts/start.sh stop

第二部分 地平线RDK3 AI摄像机产品部署与问题分析

一、产品部署流程图

┌─────────────────────────────────────────────────────────────────────────────┐
│                           部署阶段时间线                                      │
├─────────────────────────────────────────────────────────────────────────────┤
│  Week 1-2          Week 3-4          Week 5-6          Week 7-8            │
│  ┌────────┐       ┌────────┐       ┌────────┐       ┌────────┐            │
│  │硬件准备│──────▶│环境搭建│──────▶│驱动调试│──────▶│应用移植│            │
│  └────────┘       └────────┘       └────────┘       └────────┘            │
│       │                │                │                │                 │
│       ▼                ▼                ▼                ▼                 │
│  ┌────────┐       ┌────────┐       ┌────────┐       ┌────────┐            │
│  │模型转换│──────▶│ISP调优│──────▶│联调测试│──────▶│量产发布│            │
│  └────────┘       └────────┘       └────────┘       └────────┘            │
└─────────────────────────────────────────────────────────────────────────────┘
​
┌─────────────────────────────────────────────────────────────────────────────┐
│                           详细部署步骤                                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  1. 硬件准备阶段                                                             │
│  ├── RDK3开发板确认版本 (v1.2/v1.3)                                         │
│  ├── IMX415传感器模组焊接与测试                                              │
│  ├── 电源管理验证 (5V/3A 纹波<50mV)                                         │
│  └── 散热方案确认 (被动散热+导热硅脂)                                        │
│                                                                             │
│  2. 环境搭建阶段                                                             │
│  ├── Ubuntu 20.04交叉编译环境                                               │
│  ├── SDK安装 (hb_sdk-1.8.0)                                                │
│  ├── 依赖库编译 (opencv, yaml-cpp, protobuf)                                │
│  └── NFS/TFTP网络调试环境配置                                                │
│                                                                             │
│  3. 驱动调试阶段                                                             │
│  ├── U-Boot适配 (DDR参数校准)                                               │
│  ├── Kernel DTS修改 (GPIO复用冲突)                                          │
│  ├── 传感器驱动调试 (MIPI信号眼图)                                           │
│  └── 双架构IPC验证 (RPMSG通信)                                              │
│                                                                             │
│  4. ISP调优阶段                                                              │
│  ├── 黑电平校准 (不同增益下的BLC)                                            │
│  ├── 镜头阴影校正 (LSC表生成)                                                │
│  ├── 色彩校正矩阵 (CCM标定)                                                 │
│  └── 降噪与锐化平衡                                                          │
│                                                                             │
│  5. AI模型转换阶段                                                            │
│  ├── PyTorch → ONNX → HBM转换                                              │
│  ├── 量化校准 (INT8精度损失评估)                                             │
│  ├── 多核BPU负载分配                                                        │
│  └── 推理延迟优化 (Pipeline并行)                                             │
│                                                                             │
│  6. 应用集成阶段                                                             │
│  ├── 内存池大小调优                                                          │
│  ├── 时移缓存环形队列验证                                                    │
│  ├── 事件循环优先级测试                                                      │
│  └── 异常恢复机制 (Watchdog)                                                │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

二、遇到的主要问题树形分析

主要问题分类
│
├── 1. 硬件相关问题
│   ├── 1.1 电源纹波导致ISP图像条纹
│   │   ├── 现象:画面出现50Hz滚动横条纹
│   │   ├── 原因:传感器AVDD供电纹波>100mV
│   │   ├── 解决:增加LC滤波电路 + 软件启用内置DCDC
│   │   └── 验证:示波器测量纹波<30mV
│   │
│   ├── 1.2 DDR信号完整性问题
│   │   ├── 现象:高温60°C下随机死机
│   │   ├── 原因:Read/Write Leveling未优化
│   │   ├── 解决:使用地平线DDR训练工具重新校准
│   │   └── 验证:memtester 48小时压力测试
│   │
│   └── 1.3 MIPI信号眼图闭合
│       ├── 现象:高速模式(2.5Gbps)丢帧
│       ├── 原因:PCB走线等长误差>5mil
│       ├── 解决:降低速率至1.5Gbps + 软件重传机制
│       └── 验证:示波器眼图测试 + 误码率<1e-12
│
├── 2. 软件架构问题
│   ├── 2.1 双架构符号冲突
│   │   ├── 现象:链接器报multiple definition
│   │   ├── 原因:ARM-Linux和ARM-None的stdlib冲突
│   │   ├── 解决:隔离编译域 + 自定义链接脚本
│   │   └── 代码示例:
│   │       # ARM-None使用 -ffreestanding -nostdlib
│   │       # ARM-Linux使用 -lstdc++ -lgcc
│   │
│   ├── 2.2 IPC环形缓冲区假共享
│   │   ├── 现象:双核通信延迟抖动大(50us→500us)
│   │   ├── 原因:读写索引在同一缓存行
│   │   ├── 解决:__attribute__((aligned(64)))填充
│   │   └── 验证:perf c2c检测false sharing
│   │
│   ├── 2.3 内存池碎片化
│   │   ├── 现象:运行7天后malloc失败
│   │   ├── 原因:固定大小SLAB + 变长请求混用
│   │   ├── 解决:分离CMA池(大块)和SLAB池(小块)
│   │   └── 验证:valgrind massif堆分析
│   │
│   └── 2.4 观察者模式死锁
│       ├── 现象:事件循环随机卡死
│       ├── 原因:观察者回调中又publish事件
│       ├── 解决:异步队列 + 递归检测
│       └── 验证:helgrind线程竞争检测
│
├── 3. AI/ISP协同问题
│   ├── 3.1 ISP预处理导致AI精度下降
│   │   ├── 现象:暗光下检测率<60%
│   │   ├── 原因:ISP去噪过度抹除纹理
│   │   ├── 解决:双Pipeline (YUV编码 + RAW推理)
│   │   └── 验证:对比测试(原图vs处理后)
│   │
│   ├── 3.2 BPU与CPU共享DDR带宽冲突
│   │   ├── 现象:推理+编码同时执行掉帧
│   │   ├── 原因:DDR带宽争抢 (理论12GB/s)
│   │   ├── 解决:QoS优先级 + 帧间隔错峰
│   │   └── 验证:ddr_bwmon工具监控
│   │
│   └── 3.3 3A策略收敛慢
│       ├── 现象:场景切换后曝光闪烁5秒
│       ├── 原因:PID参数保守 + 帧率限制
│       ├── 解决:自适应PID + 前馈控制
│       └── 验证:录制视频逐帧分析亮度曲线
│
└── 4. 稳定性问题
    ├── 4.1 长时间运行内存泄漏
    │   ├── 现象:RSS持续增长至OOM
    │   ├── 原因:AI任务对象未正确释放
    │   ├── 解决:引入对象池 + 泄漏检测
    │   └── 验证:valgrind --leak-check=full
    │
    ├── 4.2 时移缓存越界
    │   ├── 现象:回放时随机Segmentation Fault
    │   ├── 原因:环形队列头尾指针并发更新
    │   ├── 解决:CAS原子操作 + 读写锁升级
    │   └── 验证:ThreadSanitizer检测
    │
    └── 4.3 高温降频策略触发
        ├── 现象:温度>80°C后系统卡顿
        ├── 原因:CPU/BPU降频到800MHz
        ├── 解决:提前降帧 + 风扇控制
        └── 验证:/sys/class/thermal监控

三、工具与调试手段

┌─────────────────────────────────────────────────────────────────────────────┐
│                          调试工具矩阵                                        │
├──────────────┬─────────────────────┬───────────────────────────────────────┤
│   类别       │      工具            │              使用场景                 │
├──────────────┼─────────────────────┼───────────────────────────────────────┤
│ 代码调试     │ gdb + gdb-multiarch  │ 双架构核心转储分析                    │
│              │ addr2line            │ 崩溃地址反解                          │
│              │ strace               │ 系统调用追踪                          │
├──────────────┼─────────────────────┼───────────────────────────────────────┤
│ 内存分析     │ valgrind (memcheck)  │ 内存泄漏/越界检测                     │
│              │ heaptrack            │ 堆内存分配追踪                        │
│              │ mtrace               │ glibc内存钩子                         │
├──────────────┼─────────────────────┼───────────────────────────────────────┤
│ 性能分析     │ perf                 │ CPU/BPU事件采样                       │
│              │ hb_perf (地平线工具) │ BPU算子耗时分析                       │
│              │ ftrace               │ 内核函数追踪                          │
├──────────────┼─────────────────────┼───────────────────────────────────────┤
│ 并发调试     │ helgrind             │ 线程竞争检测                          │
│              │ drd                  │ 数据竞争检测                          │
│              │ ThreadSanitizer      │ 运行时线程问题                        │
├──────────────┼─────────────────────┼───────────────────────────────────────┤
│ ISP调优      │ hb_isp_tool          │ 在线调整ISP参数                       │
│              │ 3A调试工具           │ AE/AWB/AF曲线可视化                   │
│              │ RAW数据抓取          │ 原始Bayer数据分析                     │
├──────────────┼─────────────────────┼───────────────────────────────────────┤
│ 网络调试     │ tcpdump              │ RTSP流分析                            │
│              │ iperf3               │ 网络带宽测试                          │
│              │ Wireshark            │ 协议分析                              │
├──────────────┼─────────────────────┼───────────────────────────────────────┤
│ 硬件调试     │ 示波器(1GHz+)        │ MIPI/DDR信号测量                      │
│              │ 逻辑分析仪           │ I2C/SPI时序分析                       │
│              │ 万用表               │ 电源纹波测量                          │
├──────────────┼─────────────────────┼───────────────────────────────────────┤
│ 日志系统     │ syslog               │ 系统日志收集                          │
│              │ 自定义ringbuffer     │ 崩溃前日志保存                        │
│              │ 远程日志(udp)        │ 无串口环境调试                        │
└──────────────┴─────────────────────┴───────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────┐
│                       调试手段流程图                                         │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  问题复现                                                                    │
│     │                                                                       │
│     ▼                                                                       │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │ 1. 最小化复现用例                                                      │  │
│  │    - 剥离业务逻辑,只保留核心路径                                       │  │
│  │    - 固定输入数据(RAW图/脚本)                                          │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
│     │                                                                       │
│     ▼                                                                       │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │ 2. 添加调试桩                                                          │  │
│  │    - 关键路径添加LOG_DEBUG                                            │  │
│  │    - 断言检查(assert/invariant)                                       │  │
│  │    - 性能计数器(perf counter)                                         │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
│     │                                                                       │
│     ▼                                                                       │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │ 3. 远程调试                                                            │  │
│  │    - gdbserver + 交叉gdb                                             │  │
│  │    - 核心转储分析(coredumpctl)                                        │  │
│  │    - 反汇编(objdump -dS)                                             │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
│     │                                                                       │
│     ▼                                                                       │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │ 4. 压力测试                                                            │  │
│  │    - 长时间运行(48-72小时)                                            │  │
│  │    - 极端条件(高温/低温/振动)                                          │  │
│  │    - 异常注入(断电/断网/信号干扰)                                      │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
│     │                                                                       │
│     ▼                                                                       │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │ 5. 根因分析                                                            │  │
│  │    - git bisect定位引入提交                                           │  │
│  │    - 代码覆盖率(gcov/lcov)                                            │  │
│  │    - 静态分析(cppcheck/clang-tidy)                                    │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

四、修改频率最高的代码(热点分析)

┌─────────────────────────────────────────────────────────────────────────────┐
│                       代码修改频率热力图                                      │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ████████████████████████████████████████  isp_tuning.c (35%)              │
│  │  修改原因:场景适应性差,需要反复调优                                      │
│  │  主要改动:                                                              │
│  │    - 黑电平校正参数 (15次迭代)                                           │
│  │    - 色彩矩阵系数 (12次)                                                 │
│  │    - 降噪强度曲线 (10次)                                                 │
│  │    - AE收敛速度 (8次)                                                   │
│  │                                                                          │
│  ██████████████████████████████████        ai_pipeline.c (28%)             │
│  │  修改原因:模型升级 + 精度优化                                           │
│  │  主要改动:                                                              │
│  │    - 预处理归一化参数 (模型版本升级)                                      │
│  │    - NMS阈值调整 (6次)                                                   │
│  │    - 跟踪器匹配算法 (4次)                                                │
│  │    - 后处理解码优化 (3次)                                                │
│  │                                                                          │
│  ██████████████████████████              memory_manager.c (18%)            │
│  │  修改原因:内存泄漏 + 碎片化                                             │
│  │  主要改动:                                                              │
│  │    - 池大小调整 (8次)                                                    │
│  │    - 对齐策略修改 (5次)                                                  │
│  │    - 泄漏检测增强 (4次)                                                  │
│  │                                                                          │
│  ██████████████████                      event_loop.c (12%)                │
│  │  修改原因:优先级调度 + 死锁修复                                         │
│  │  主要改动:                                                              │
│  │    - 事件优先级调整 (6次)                                                │
│  │    - 锁粒度优化 (4次)                                                    │
│  │    - 定时器精度改进 (3次)                                                │
│  │                                                                          │
│  ██████████                              ipc_bus.c (7%)                    │
│  │  修改原因:双架构通信延迟                                               │
│  │  主要改动:                                                              │
│  │    - 缓存行对齐 (3次)                                                    │
│  │    - 超时策略调整 (2次)                                                  │
│  │    - 重传机制 (2次)                                                      │
│  │                                                                          │
└─────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────┐
│                       修改原因分类统计                                       │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  功能迭代 (45%)                                                              │
│  ├── 客户需求变更 (20%)                                                     │
│  ├── 场景适应性 (15%)                                                       │
│  └── 新功能添加 (10%)                                                       │
│                                                                             │
│  缺陷修复 (30%)                                                              │
│  ├── 内存问题 (12%)                                                         │
│  ├── 并发问题 (10%)                                                         │
│  └── 边界条件 (8%)                                                          │
│                                                                             │
│  性能优化 (15%)                                                              │
│  ├── 延迟优化 (8%)                                                          │
│  ├── 吞吐量提升 (5%)                                                        │
│  └── 功耗优化 (2%)                                                          │
│                                                                             │
│  平台适配 (10%)                                                              │
│  ├── SDK版本升级 (6%)                                                       │
│  ├── 硬件改版 (3%)                                                          │
│  └── 工具链更新 (1%)                                                        │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

五、产品演进感悟树形分析

产品演进感悟
│
├── 1. 架构设计层面
│   ├── 1.1 模块化重要性
│   │   ├── 教训:初期耦合度过高,ISP调优牵一发动全身
│   │   ├── 改进:定义清晰接口(isp_ops/ai_ops)
│   │   └── 效果:V2.0版本模块替换工作量减少70%
│   │
│   ├── 1.2 配置外置化
│   │   ├── 教训:硬编码参数导致每次调优需重新编译
│   │   ├── 改进:YAML配置文件 + 热加载
│   │   └── 效果:调优周期从2天缩短到2小时
│   │
│   ├── 1.3 可观测性设计
│   │   ├── 教训:线上问题无法复现时束手无策
│   │   ├── 改进:结构化日志 + 指标暴露(Prometheus)
│   │   └── 效果:MTTR从4小时降至30分钟
│   │
│   └── 1.4 防御性编程
│       ├── 教训:单点故障导致系统崩溃
│       ├── 改进:Watchdog + 降级策略 + 热备
│       └── 效果:可用性从99.5%提升到99.95%
│
├── 2. 开发流程层面
│   ├── 2.1 持续集成
│   │   ├── 初期:手动测试,发布周期2周
│   │   ├── 改进:自动化测试(单元+集成+压力)
│   │   └── 当前:CI触发,发布周期1天
│   │
│   ├── 2.2 代码审查
│   │   ├── 教训:低级错误重复出现
│   │   ├── 改进:强制Review + CheckList
│   │   └── 效果:缺陷率降低60%
│   │
│   ├── 2.3 文档同步
│   │   ├── 教训:文档滞后代码,知识流失
│   │   ├── 改进:Doxygen + 架构决策记录(ADR)
│   │   └── 效果:新人上手时间从4周减至1周
│   │
│   └── 2.4 版本管理
│       ├── 教训:紧急修复引入新问题
│       ├── 改进:Git Flow + 语义化版本
│       └── 效果:回滚次数减少80%
│
├── 3. 调试方法论
│   ├── 3.1 从现象到根因
│   │   ├── 经验:不要相信"不可能"的问题
│   │   ├── 案例:IPC延迟抖动→缓存行假共享
│   │   └── 方法:5 Whys分析法
│   │
│   ├── 3.2 数据驱动调试
│   │   ├── 经验:加日志比猜原因更高效
│   │   ├── 案例:内存泄漏→valgrind定位
│   │   └── 方法:先量化,再优化
│   │
│   ├── 3.3 自动化测试
│   │   ├── 经验:手动测试覆盖不全
│   │   ├── 案例:并发bug只在压力下出现
│   │   └── 方法:混沌工程 + 模糊测试
│   │
│   └── 3.4 工具链熟练度
│       ├── 经验:掌握工具事半功倍
│       ├── 案例:perf发现BPU空闲等待
│       └── 方法:工具卡组(cheatsheet)
│
└── 4. 团队协作层面
    ├── 4.1 知识共享
    │   ├── 教训:模块隔离导致重复造轮子
    │   ├── 改进:技术分享会 + Wiki
    │   └── 效果:代码复用率提升40%
    │
    ├── 4.2 问题复盘
    │   ├── 教训:同一问题反复出现
    │   ├── 改进:RCA报告 + 措施跟踪
    │   └── 效果:重犯问题归零
    │
    ├── 4.3 需求管理
    │   ├── 教训:需求变更导致返工
    │   ├── 改进:接口先行 + 原型验证
    │   └── 效果:返工成本降低50%
    │
    └── 4.4 技术债务
        ├── 教训:妥协方案积累成技术债务
        ├── 改进:定期重构 + 债务评估
        └── 效果:维护成本逐年下降

六、关键经验总结

┌─────────────────────────────────────────────────────────────────────────────┐
│                          核心经验教训                                         │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ✅ DO - 应该做的                                                           │
│  ├── 1. 内存池化管理:预分配+复用,避免运行时分配                            │
│  ├── 2. 异步日志系统:独立线程+环形缓冲,不影响主流程                        │
│  ├── 3. 观察者模式:解耦事件源与处理器,易于扩展                             │
│  ├── 4. 配置外置:所有可调参数放入配置文件                                   │
│  ├── 5. 健康检查:定期上报CPU/内存/温度,预警机制                            │
│  ├── 6. 版本兼容:API版本号,平滑升级                                       │
│  └── 7. 压力测试:发布前48小时稳定性测试                                     │
│                                                                             │
│  ❌ DON'T - 避免做的                                                         │
│  ├── 1. 硬编码参数:调优痛苦,重新编译                                       │
│  ├── 2. 过度优化:牺牲可读性的微优化                                        │
│  ├── 3. 忽略边界:空指针/数组越界/除零                                      │
│  ├── 4. 全局变量泛滥:状态不可预测                                          │
│  ├── 5. 长函数(>200行):难以理解和测试                                      │
│  ├── 6. 魔法数字:晦涩难懂                                                  │
│  └── 7. 死代码:增加维护负担                                                │
│                                                                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                          量化成果                                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  指标                     V1.0         V2.0        改善                     │
│  ───────────────────────────────────────────────────────────────────────   │
│  启动时间(s)              8.5          3.2         -62%                     │
│  内存占用(MB)             512          328         -36%                     │
│  推理延迟(ms)             45           28          -38%                     │
│  CPU使用率(%)             85           52          -39%                     │
│  MTBF(小时)               72           500+        +594%                    │
│  代码行数                 15000        8500        -43%                     │
│  单元覆盖率(%)            20           78          +290%                    │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

"嵌入式AI产品不是简单地把模型跑起来,而是硬件、软件、算法的系统工程。最大的感悟是:先跑通,再跑稳,最后跑优。“

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐