第一部分:OpenIPC整体架构树形结构

openipc/
├── 📁 firmware/                 # 主固件构建系统
│   ├── 📁 board/                # 板级配置
│   │   ├── 📁 hisilicon/        # 海思平台
│   │   │   ├── hi3516cv300/
│   │   │   ├── hi3516ev200/
│   │   │   └── hi3519v101/
│   │   ├── 📁 sigmastar/        # 星宸科技平台
│   │   │   ├── ssc335/
│   │   │   ├── ssc337/
│   │   │   └── ssr305/          # SSR305芯片支持
│   │   └── 📁 goke/             # 国科平台
│   ├── 📁 package/               # 软件包配置
│   │   ├── 📁 majestic/         # 流媒体核心
│   │   ├── 📁 openipc-tools/    # 工具集
│   │   └── 📁 webui/            # Web界面
│   └── 📁 configs/               # 构建配置
│
├── 📁 linux/                     # Linux内核源码
│   ├── 📁 arch/                  # 架构相关代码
│   │   └── 📁 arm/               # ARM架构
│   │       ├── mach-hisi/        # 海思平台
│   │       └── mach-infinity/    # 星宸平台
│   ├── 📁 drivers/               # 设备驱动
│   │   ├── 📁 media/             # 多媒体驱动
│   │   │   ├── platform/         # 平台相关
│   │   │   │   ├── hisi/         # 海思VI/VPSS/VENC
│   │   │   │   └── infinity/     # 星宸ISP驱动
│   │   │   └── i2c/              # 传感器驱动
│   │   │       ├── imx335.c      # 索尼传感器
│   │   │       ├── imx307.c
│   │   │       └── sc2235.c      # 思特威传感器
│   │   └── 📁 spi/                # SPI接口驱动
│   └── 📁 include/                # 内核头文件
│
├── 📁 uboot/                      # U-Boot启动加载器
│   ├── 📁 board/                  # 板级支持
│   ├── 📁 drivers/                # 驱动
│   └── 📁 include/                # 头文件
│
├── 📁 majestic/                   # 流媒体服务
│   ├── 📁 src/                    # 源码
│   │   ├── 📁 encoder/            # 编码器模块
│   │   │   ├── h264_encoder.c     # H.264编码
│   │   │   ├── h265_encoder.c     # H.265编码
│   │   │   └── mjpeg_encoder.c    # MJPEG编码
│   │   ├── 📁 streaming/          # 流媒体处理
│   │   │   ├── rtsp_server.c      # RTSP服务器
│   │   │   ├── onvif_server.c     # ONVIF实现
│   │   │   └── webrtc_stream.c    # WebRTC支持
│   │   ├── 📁 osd/                 # OSD叠加
│   │   │   ├── osd_manager.c      # OSD管理
│   │   │   └── font_render.c      # 字体渲染
│   │   └── 📁 config/              # 配置管理
│   │       └── yaml_config.c      # YAML解析
│   └── 📁 include/                 # 公共头文件
│
├── 📁 majestic-plugins/           # 插件系统
│   ├── 📁 plugins/                # 插件实现
│   │   ├── 📁 motion_detection/   # 运动检测
│   │   ├── 📁 face_detection/     # 人脸检测
│   │   └── 📁 audio_alert/        # 音频告警
│   └── 📁 sdk/                    # 插件SDK
│
├── 📁 microbe-webui/             # 轻量级WebUI
│   ├── 📁 src/                    # 源码
│   │   ├── 📁 pages/              # 页面
│   │   ├── 📁 components/         # 组件
│   │   └── 📁 api/                # API接口
│   └── 📁 public/                 # 静态资源
│
└── 📁 tools/                      # 工具集合
    ├── 📁 ipctool/                # 硬件检测工具
    ├── 📁 yaml-cli/               # YAML配置工具
    └── 📁 sysupgrade/             # 系统升级工具

第二部分:关键代码深度分析

1.Majestic流媒体核心代码分析

1.1文件:majestic/src/encoder/h265_encoder.c
/**
 * @file h265_encoder.c
 * @brief H.265/HEVC视频编码器实现
 * @author OpenIPC Team
 * @version 1.0.0
 * @date 2024
 * 
 * @details 该模块实现了基于硬件加速的H.265编码功能,
 *          支持动态码率调整、GOP结构配置和多码流输出。
 *          关键数据结构:encoder_context_t 管理编码会话状态,
 *          frame_buffer_t 处理视频帧缓冲队列。
 * 
 * @note 依赖硬件VPU(视频处理单元),需要内核驱动支持
 * @copyright Copyright (c) 2024 OpenIPC
 */
​
#include "encoder.h"
#include <linux/videodev2.h>
​
/**
 * @defgroup H265_Constants H.265编码常量定义
 * @{
 */
#define H265_MIN_BITRATE      (64 * 1024)      /**< 最小码率:64kbps */
#define H265_MAX_BITRATE      (20 * 1024 * 1024) /**< 最大码率:20Mbps */
#define H265_DEFAULT_FPS      25                /**< 默认帧率:25fps */
#define H265_DEFAULT_GOP_SIZE  50               /**< 默认GOP大小:2秒 @ 25fps */
#define H265_MAX_B_FRAMES      2                /**< 最大B帧数量 */
/** @} */
​
/**
 * @enum h265_profile_t
 * @brief H.265编码档次配置
 */
typedef enum {
    H265_PROFILE_MAIN,        /**< Main profile, 8bit色深支持 */
    H265_PROFILE_MAIN10,      /**< Main10 profile, 10bit色深支持 */
    H265_PROFILE_MAIN_STILL   /**< Main Still Picture profile */
} h265_profile_t;
​
/**
 * @struct h265_config_t
 * @brief H.265编码器配置参数结构体
 * 
 * @var h265_config_t::width
 *  编码宽度,必须是16的倍数,最小176,最大3840
 * @var h265_config_t::height
 *  编码高度,必须是16的倍数,最小144,最大2160
 * @var h265_config_t::bitrate
 *  目标码率,单位bps,受H265_MIN_BITRATE和H265_MAX_BITRATE限制
 * @var h265_config_t::fps
 *  编码帧率,范围1-120fps
 */
typedef struct {
    uint32_t width;           /**< 视频宽度,单位:像素 */
    uint32_t height;          /**< 视频高度,单位:像素 */
    uint32_t bitrate;         /**< 编码码率,单位:bps */
    uint8_t fps;              /**< 帧率,单位:fps */
    uint8_t gop_size;         /**< GOP大小(I帧间隔) */
    h265_profile_t profile;   /**< 编码档次 */
    bool enable_cbr;          /**< 是否启用恒定码率模式 */
} h265_config_t;
​
/**
 * @struct encoder_stats_t
 * @brief 编码器统计信息
 * 
 * @var encoder_stats_t::encoded_frames
 *  已编码帧总数,uint64_t类型防止32位溢出
 * @var encoder_stats_t::total_bytes
 *  输出码流总字节数,用于计算平均码率
 * @var encoder_stats_t::fps_current
 *  当前实时帧率,通过时间窗口计算
 */
typedef struct {
    uint64_t encoded_frames;  /**< 已编码帧总数 */
    uint64_t total_bytes;     /**< 输出码流总字节数 */
    float fps_current;        /**< 当前实时帧率 */
    uint32_t dropped_frames;  /**< 丢帧计数 */
} encoder_stats_t;
​
/**
 * @brief 初始化H.265编码器实例
 * @param config 编码器配置参数指针
 * @return int 成功返回文件描述符,失败返回负值错误码
 * 
 * @retval >0 编码器实例句柄
 * @retval -EINVAL 参数无效
 * @retval -ENOMEM 内存分配失败
 * @retval -EIO 硬件初始化失败
 * 
 * @code{.c}
 * h265_config_t cfg = {
 *     .width = 1920,
 *     .height = 1080,
 *     .bitrate = 4096 * 1024, // 4Mbps
 *     .fps = 30,
 *     .gop_size = 60,
 *     .profile = H265_PROFILE_MAIN
 * };
 * int encoder_fd = h265_encoder_init(&cfg);
 * @endcode
 */
int h265_encoder_init(const h265_config_t *config)
{
    int ret;
    struct v4l2_format fmt;
    struct v4l2_ext_control ctrl[8];
    struct v4l2_ext_controls ctrls;
    
    /* 参数验证:检查指针和数值范围 */
    if (!config) {
        return -EINVAL;  // 空指针错误
    }
    
    /* 分辨率验证:确保符合硬件限制 */
    if (config->width % 16 != 0 || config->height % 16 != 0) {
        return -EINVAL;  // 分辨率必须是16的倍数
    }
    
    if (config->bitrate < H265_MIN_BITRATE || 
        config->bitrate > H265_MAX_BITRATE) {
        return -EINVAL;  // 码率超出范围
    }
    
    /* 打开V4L2编码设备 */
    int fd = open("/dev/video0", O_RDWR);
    if (fd < 0) {
        return -EIO;  // 设备打开失败
    }
    
    /* 配置编码格式 */
    memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
    fmt.fmt.pix_mp.width = config->width;
    fmt.fmt.pix_mp.height = config->height;
    fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;  // 输入格式:NV12
    fmt.fmt.pix_mp.field = V4L2_FIELD_NONE;
    fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709;
    
    ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
    if (ret < 0) {
        close(fd);
        return -EIO;
    }
    
    /* 设置编码参数 */
    memset(&ctrls, 0, sizeof(ctrls));
    ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
    ctrls.count = 6;
    ctrls.controls = ctrl;
    
    ctrl[0].id = V4L2_CID_MPEG_VIDEO_BITRATE;
    ctrl[0].value = config->bitrate;
    
    ctrl[1].id = V4L2_CID_MPEG_VIDEO_H265_PROFILE;
    ctrl[1].value = config->profile;
    
    ctrl[2].id = V4L2_CID_MPEG_VIDEO_H265_I_FRAME_QP;
    ctrl[2].value = 26;  // I帧量化参数
    
    ctrl[3].id = V4L2_CID_MPEG_VIDEO_H265_P_FRAME_QP;
    ctrl[3].value = 28;  // P帧量化参数
    
    ctrl[4].id = V4L2_CID_MPEG_VIDEO_H265_B_FRAME_QP;
    ctrl[4].value = 30;  // B帧量化参数
    
    ctrl[5].id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
    ctrl[5].value = config->gop_size;
    
    ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls);
    if (ret < 0) {
        close(fd);
        return -EIO;
    }
    
    return fd;  // 返回编码器句柄
}
​
/**
 * @brief 编码一帧视频数据
 * @param fd 编码器文件描述符
 * @param frame 原始帧数据指针
 * @param size 帧数据大小(字节)
 * @param pts 显示时间戳(微秒)
 * @return int 成功返回0,失败返回负值
 * 
 * @note 输入帧格式必须是NV12,大小必须与初始化配置一致
 * @warning 该函数是阻塞调用,直到编码完成或出错才返回
 */
int h265_encoder_encode_frame(int fd, const void *frame, size_t size, uint64_t pts)
{
    struct v4l2_buffer buf;
    struct v4l2_plane planes[VIDEO_MAX_PLANES];
    int ret;
    
    /* 准备编码缓冲区 */
    memset(&buf, 0, sizeof(buf));
    buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.length = 1;
    buf.m.planes = planes;
    
    /* 查询空闲缓冲区 */
    ret = ioctl(fd, VIDIOC_DQBUF, &buf);
    if (ret < 0) {
        return -EAGAIN;  // 无可用缓冲区
    }
    
    /* 将原始帧数据复制到缓冲区 */
    memcpy(planes[0].m.userptr, frame, size);
    planes[0].bytesused = size;
    
    /* 设置时间戳 */
    buf.timestamp.tv_sec = pts / 1000000;
    buf.timestamp.tv_usec = pts % 1000000;
    
    /* 提交编码任务 */
    buf.flags |= V4L2_BUF_FLAG_TIMESTAMP_COPY;
    ret = ioctl(fd, VIDIOC_QBUF, &buf);
    if (ret < 0) {
        return -EIO;
    }
    
    return 0;
}
1.2 文件:majestic/src/streaming/rtsp_server.c
/**
 * @file rtsp_server.c
 * @brief RTSP流媒体服务器实现
 * @author OpenIPC Team
 * @version 2.1.0
 * 
 * @details 实现RFC 2326标准RTSP协议,支持DESCRIBE、SETUP、PLAY等
 *          方法。支持RTP over UDP和RTP over RTSP两种传输模式。
 *          使用epoll实现高并发连接管理。
 */
​
#include "rtsp_server.h"
#include <netinet/in.h>
#include <sys/epoll.h>
​
/**
 * @defgroup RTSP_Constants RTSP协议常量
 * @{
 */
#define RTSP_DEFAULT_PORT      554     /**< RTSP默认端口 */
#define RTSP_MAX_CLIENTS       32      /**< 最大并发客户端数 */
#define RTSP_BUFFER_SIZE       8192    /**< 协议解析缓冲区大小 */
#define RTSP_TIMEOUT_SEC       60      /**< 会话超时时间 */
/** @} */
​
/**
 * @enum rtsp_state_t
 * @brief RTSP会话状态机
 */
typedef enum {
    RTSP_STATE_INIT,      /**< 初始状态 */
    RTSP_STATE_READY,     /**< SETUP完成,等待PLAY */
    RTSP_STATE_PLAYING,   /**< PLAYING,正在传输 */
    RTSP_STATE_PAUSED,    /**< 暂停状态 */
    RTSP_STATE_TEARDOWN   /**< 会话终止 */
} rtsp_state_t;
​
/**
 * @struct rtsp_session_t
 * @brief RTSP会话结构体
 * 
 * @var rtsp_session_t::id
 *  会话唯一标识符,使用UUID生成
 * @var rtsp_session_t::state
 *  当前会话状态
 * @var rtsp_session_t::transport
 *  传输模式(UDP/TCP)
 * @var rtsp_session_t::client_port
 *  客户端RTP端口(RTP/RTCP端口对)
 */
typedef struct {
    char id[37];                    /**< 会话ID:36字符UUID + null */
    rtsp_state_t state;             /**< 会话状态 */
    int socket_fd;                  /**< 客户端socket */
    struct sockaddr_in client_addr; /**< 客户端地址 */
    
    struct {
        enum {
            RTSP_TRANSPORT_TCP,     /**< RTP over RTSP (TCP) */
            RTSP_TRANSPORT_UDP      /**< RTP over UDP */
        } mode;
        uint16_t client_rtp_port;   /**< 客户端RTP端口 */
        uint16_t client_rtcp_port;  /**< 客户端RTCP端口 */
        uint16_t server_rtp_port;   /**< 服务器RTP端口 */
    } transport;
    
    uint64_t last_active;           /**< 最后活动时间戳(毫秒) */
    uint32_t seq;                   /**< RTP序列号 */
    uint32_t ssrc;                  /**< 同步源标识 */
} rtsp_session_t;
​
/**
 * @struct rtsp_request_t
 * @brief RTSP请求解析结果
 */
typedef struct {
    char method[16];        /**< 请求方法:DESCRIBE, SETUP, PLAY等 */
    char url[256];          /**< 请求URL:rtsp://... */
    char version[10];       /**< RTSP版本:RTSP/1.0 */
    struct {
        char cseq[16];      /**< CSeq序列号 */
        char session[37];   /**< 会话ID */
        char transport[128];/**< Transport头 */
    } headers;
} rtsp_request_t;
​
/**
 * @brief 解析RTSP请求行
 * @param buffer 原始请求数据
 * @param req 解析结果输出结构体
 * @return int 成功返回0,失败返回-1
 * 
 * @example
 * 输入: "DESCRIBE rtsp://192.168.1.100/stream RTSP/1.0\r\n"
 * 输出: method="DESCRIBE", url="rtsp://192.168.1.100/stream"
 */
static int rtsp_parse_request_line(const char *buffer, rtsp_request_t *req)
{
    /* 使用sscanf解析请求行 */
    int ret = sscanf(buffer, "%15s %255s %9s", 
                     req->method, req->url, req->version);
    
    if (ret != 3) {
        return -1;  // 解析失败
    }
    
    return 0;
}
​
/**
 * @brief 处理RTSP DESCRIBE请求
 * @param session RTSP会话
 * @param req 解析后的请求
 * @return int 成功返回0
 * 
 * @details 返回SDP描述信息,包含媒体流格式:
 *          - 视频流:H.264/H.265编码参数
 *          - 音频流:AAC/G.711编码参数
 *          - 控制URL:用于后续SETUP
 */
static int rtsp_handle_describe(rtsp_session_t *session, rtsp_request_t *req)
{
    char response[RTSP_BUFFER_SIZE];
    char sdp[1024];
    
    /* 构建SDP描述 */
    snprintf(sdp, sizeof(sdp),
        "v=0\r\n"
        "o=- %ld %ld IN IP4 %s\r\n"
        "s=OpenIPC Stream\r\n"
        "c=IN IP4 0.0.0.0\r\n"
        "t=0 0\r\n"
        "m=video 0 RTP/AVP 96\r\n"
        "a=rtpmap:96 H265/90000\r\n"
        "a=control:track1\r\n"
        "m=audio 0 RTP/AVP 97\r\n"
        "a=rtpmap:97 MPEG4-GENERIC/16000/2\r\n"
        "a=control:track2\r\n",
        time(NULL), time(NULL), inet_ntoa(session->client_addr.sin_addr));
    
    /* 构建RTSP响应 */
    snprintf(response, sizeof(response),
        "RTSP/1.0 200 OK\r\n"
        "CSeq: %s\r\n"
        "Content-Type: application/sdp\r\n"
        "Content-Length: %zu\r\n"
        "\r\n"
        "%s",
        req->headers.cseq, strlen(sdp), sdp);
    
    /* 发送响应 */
    send(session->socket_fd, response, strlen(response), 0);
    
    return 0;
}

第三部分:关键数据结构与数据处理单位分析

1. 视频数据处理流水线

/**
 * @file include/media_buffer.h
 * @brief 视频缓冲区管理
 * @author OpenIPC Team
 */
​
/**
 * @defgroup Video_Data_Units 视频数据单位定义
 * @{
 */
​
/**
 * @brief 视频帧数据结构
 * 
 * 数据流:Sensor -> ISP -> VPSS -> VENC -> RTP
 * 单位转换:RAW(12-14bit) -> RGB(24-32bit) -> NV12(12bit/pixel) -> H.265(可变)
 */
typedef struct video_frame {
    uint32_t width;         /**< 宽度,单位:像素 */
    uint32_t height;        /**< 高度,单位:像素 */
    enum {
        PIX_FMT_RAW_BAYER,  /**< RAW Bayer数据,12-14bit/pixel */
        PIX_FMT_NV12,       /**< NV12格式,12bit/pixel */
        PIX_FMT_RGB24,      /**< RGB888,24bit/pixel */
        PIX_FMT_ARGB32      /**< ARGB8888,32bit/pixel */
    } format;
    
    /**
     * @brief 帧数据缓冲区
     * 
     * 大小计算公式:
     * - RAW: width * height * 14/8 (14bit RAW)
     * - NV12: width * height * 3/2 (Y:8bit + UV:8bit交错)
     * - RGB24: width * height * 3
     */
    uint8_t *data;
    size_t data_size;       /**< 实际数据大小,单位:字节 */
    
    uint64_t timestamp;     /**< 时间戳,单位:微秒 */
    uint32_t sequence;      /**< 帧序号 */
    
    /**
     * @brief 关键帧标志
     * 
     * 编码域:
     * - H.264: IDR帧
     * - H.265: IRAP帧
     */
    bool is_keyframe;
} video_frame_t;
​
/**
 * @brief 编码码流数据结构
 */
typedef struct encoded_stream {
    enum {
        STREAM_H264,        /**< H.264码流 */
        STREAM_H265,        /**< H.265/HEVC码流 */
        STREAM_MJPEG        /**< MJPEG码流 */
    } codec;
    
    /**
     * @brief 编码数据分片
     * 
     * H.265 NAL单元类型:
     * - VPS: 0x40 (视频参数集)
     * - SPS: 0x42 (序列参数集)
     * - PPS: 0x44 (图像参数集)
     * - IDR: 0x26 (关键帧)
     * - Non-IDR: 0x02 (非关键帧)
     */
    uint8_t nal_type;
    
    uint8_t *data;          /**< 编码数据 */
    size_t length;          /**< 数据长度,单位:字节 */
    
    /**
     * @brief 码率统计
     * 
     * 平均码率 = total_bytes * 8 / duration_seconds
     * 单位:bps (bits per second)
     */
    uint32_t bitrate;       /**< 瞬时码率,单位:bps */
} encoded_stream_t;
​
/** @} */
​
/**
 * @defgroup Buffer_Management 缓冲区管理
 * @{
 */
​
/**
 * @brief 视频缓冲区池
 * 
 * @details 使用内存池技术减少分配开销
 *          典型配置:6个NV12帧缓冲区,每个1920x1080
 *          内存占用:1920*1080*1.5*6 ≈ 18.7MB
 */
typedef struct buffer_pool {
    uint32_t pool_size;          /**< 缓冲区数量 */
    uint32_t buffer_size;        /**< 每个缓冲区大小,单位:字节 */
    uint8_t **buffers;           /**< 缓冲区指针数组 */
    
    /**
     * @brief 缓冲区状态位图
     * 
     * 使用位图管理缓冲区占用状态
     * 0: 空闲,1: 已占用
     * 支持原子操作实现无锁访问
     */
    uint32_t *occupied_bitmap;
    
    uint32_t alloc_count;        /**< 已分配计数 */
    uint32_t peak_alloc;         /**< 峰值分配数 */
} buffer_pool_t;
​
/**
 * @brief 从池中分配缓冲区
 * @param pool 缓冲区池
 * @param size 请求大小
 * @return uint8_t* 成功返回缓冲区指针,失败返回NULL
 * 
 * @note 使用原子位操作实现无锁分配
 * @see buffer_pool_t::occupied_bitmap
 */
static inline uint8_t *buffer_pool_alloc(buffer_pool_t *pool, size_t size)
{
    uint32_t i;
    
    if (size > pool->buffer_size) {
        return NULL;  // 请求过大
    }
    
    /* 遍历查找空闲位 */
    for (i = 0; i < pool->pool_size; i++) {
        uint32_t word_idx = i / 32;
        uint32_t bit_idx = i % 32;
        uint32_t mask = 1 << bit_idx;
        
        /* 原子测试并设置 */
        if (!(__atomic_test_and_set(&pool->occupied_bitmap[word_idx], 
                                    mask, __ATOMIC_ACQUIRE))) {
            pool->alloc_count++;
            if (pool->alloc_count > pool->peak_alloc) {
                pool->peak_alloc = pool->alloc_count;
            }
            return pool->buffers[i];
        }
    }
    
    return NULL;  // 无可用缓冲区
}

第四部分:SSR305特定代码分析

1. 文件:linux/drivers/media/platform/infinity/ssr305_isp.c

/**
 * @file ssr305_isp.c
 * @brief SSR305芯片ISP(图像信号处理器)驱动
 * @author SigmaStar/OpenIPC
 * @version 1.2.0
 * 
 * @details 针对SSR305芯片的ISP驱动实现
 *          关键特性:
 *          - 3D降噪硬件加速
 *          - WDR(宽动态)处理
 *          - 黑光全彩模式
 *          - 低功耗状态管理
 */
​
#include <linux/module.h>
#include <linux/platform_device.h>
#include <media/v4l2-subdev.h>
​
/**
 * @defgroup SSR305_ISP_Registers SSR305 ISP寄存器定义
 * @{
 */
​
#define SSR305_ISP_BASE         0xA0800000  /**< ISP寄存器基址 */
#define SSR305_ISP_SIZE         0x10000     /**< 寄存器空间大小 */
​
/* 核心控制寄存器 */
#define REG_ISP_CTRL            0x0000      /**< ISP控制寄存器 */
#define REG_ISP_STATUS          0x0004      /**< ISP状态寄存器 */
#define REG_ISP_INT_EN          0x0008      /**< 中断使能寄存器 */
#define REG_ISP_INT_STATUS      0x000C      /**< 中断状态寄存器 */
​
/* 3DNR(3D降噪)模块寄存器 */
#define REG_3DNR_CTRL           0x1000      /**< 3DNR控制 */
#define REG_3DNR_STRENGTH       0x1004      /**< 降噪强度:0-255 */
#define REG_3DNR_MOTION          0x1008      /**< 运动检测阈值 */
​
/* WDR(宽动态)寄存器 */
#define REG_WDR_CTRL            0x2000      /**< WDR控制 */
#define REG_WDR_MODE            0x2004      /**< WDR模式:0-关闭,1-线间,2-帧间 */
#define REG_WDR_RATIO           0x2008      /**< WDR合成比例 */
​
/* 低功耗管理 */
#define REG_PMU_CTRL            0x3000      /**< 电源管理控制 */
#define REG_PMU_STATUS          0x3004      /**< 电源状态 */
​
/** @} */
​
/**
 * @struct ssr305_isp_dev
 * @brief SSR305 ISP设备结构体
 */
struct ssr305_isp_dev {
    struct device *dev;          /**< 设备指针 */
    struct v4l2_subdev subdev;   /**< V4L2子设备 */
    struct v4l2_ctrl_handler ctrl_handler; /**< 控制句柄 */
    
    void __iomem *base;          /**< 寄存器基址 */
    struct clk *clk;             /**< 时钟 */
    struct regulator *regulator; /**< 电源调节器 */
    
    /**
     * @struct isp_config
     * @brief ISP运行时配置
     */
    struct {
        uint32_t width;          /**< 图像宽度 */
        uint32_t height;         /**< 图像高度 */
        uint32_t fps;            /**< 帧率 */
        uint32_t hdr_mode;       /**< HDR模式 */
        uint32_t nr_strength;    /**< 降噪强度 */
        bool low_power;          /**< 低功耗模式 */
    } config;
    
    /* 统计信息 */
    struct {
        uint64_t frame_count;    /**< 帧计数 */
        uint64_t dropped_count;  /**< 丢帧计数 */
        uint32_t current_fps;    /**< 当前帧率 */
        uint32_t temperature;    /**< 芯片温度 */
    } stats;
};
​
/**
 * @brief 设置3DNR(3D降噪)参数
 * @param isp ISP设备指针
 * @param strength 降噪强度 (0-255)
 * @return int 0成功,负值失败
 * 
 * @details 3DNR算法:
 *          时域滤波: Y_t = α * Y_t-1 + (1-α) * Y_t
 *          运动补偿: 根据REG_3DNR_MOTION调整α值
 */
static int ssr305_isp_set_3dnr(struct ssr305_isp_dev *isp, uint8_t strength)
{
    uint32_t reg_val;
    
    if (strength > 255) {
        dev_err(isp->dev, "Invalid 3DNR strength: %d\n", strength);
        return -EINVAL;
    }
    
    /* 设置降噪强度 */
    writel(strength, isp->base + REG_3DNR_STRENGTH);
    
    /* 根据强度自动调整运动阈值 */
    reg_val = readl(isp->base + REG_3DNR_MOTION);
    if (strength < 50) {
        /* 低强度:运动敏感 */
        reg_val = 10;
    } else if (strength < 150) {
        /* 中强度:平衡 */
        reg_val = 30;
    } else {
        /* 高强度:运动不敏感,防止拖影 */
        reg_val = 60;
    }
    writel(reg_val, isp->base + REG_3DNR_MOTION);
    
    /* 启用3DNR */
    reg_val = readl(isp->base + REG_3DNR_CTRL);
    reg_val |= BIT(0);  /* 使能位 */
    writel(reg_val, isp->base + REG_3DNR_CTRL);
    
    isp->config.nr_strength = strength;
    dev_dbg(isp->dev, "3DNR set: strength=%d, motion=%d\n", 
            strength, reg_val);
    
    return 0;
}
​
/**
 * @brief 配置WDR(宽动态)模式
 * @param isp ISP设备指针
 * @param mode WDR模式
 * @param ratio 合成比例
 * 
 * @details WDR模式:
 *          0: 关闭 - 标准线性模式
 *          1: 线间WDR - 同一帧内长短曝光交替
 *          2: 帧间WDR - 长短帧合成
 *          
 *          动态范围提升:
 *          线间WDR: +24dB
 *          帧间WDR: +30dB
 */
static void ssr305_isp_set_wdr(struct ssr305_isp_dev *isp, int mode, int ratio)
{
    uint32_t reg_val;
    
    /* 设置WDR模式 */
    reg_val = readl(isp->base + REG_WDR_MODE);
    reg_val &= ~0x3;
    reg_val |= (mode & 0x3);
    writel(reg_val, isp->base + REG_WDR_MODE);
    
    /* 设置合成比例 */
    writel(ratio, isp->base + REG_WDR_RATIO);
    
    /* 启用WDR */
    reg_val = readl(isp->base + REG_WDR_CTRL);
    if (mode > 0) {
        reg_val |= BIT(0);  /* 使能 */
        dev_info(isp->dev, "WDR enabled: mode=%d, ratio=%d\n", mode, ratio);
    } else {
        reg_val &= ~BIT(0); /* 禁用 */
        dev_info(isp->dev, "WDR disabled\n");
    }
    writel(reg_val, isp->base + REG_WDR_CTRL);
}
​
/**
 * @brief 设置低功耗模式
 * @param isp ISP设备指针
 * @param enable true:进入低功耗,false:唤醒
 * 
 * @details SSR305低功耗特性:
 *          待机电流:< 5mA
 *          唤醒时间:< 10ms
 *          支持PIR运动唤醒
 */
static int ssr305_isp_set_low_power(struct ssr305_isp_dev *isp, bool enable)
{
    uint32_t reg_val;
    
    reg_val = readl(isp->base + REG_PMU_CTRL);
    
    if (enable) {
        /* 进入低功耗模式 */
        reg_val |= BIT(0);  /* 睡眠使能 */
        
        /* 配置唤醒源:PIR/RTC/网络 */
        reg_val |= BIT(4);  /* PIR唤醒使能 */
        reg_val |= BIT(5);  /* RTC唤醒使能 */
        
        /* 关闭不必要的时钟 */
        clk_disable_unprepare(isp->clk);
        
        isp->config.low_power = true;
        dev_info(isp->dev, "Entering low power mode\n");
    } else {
        /* 唤醒 */
        reg_val &= ~BIT(0); /* 清除睡眠位 */
        
        /* 恢复时钟 */
        clk_prepare_enable(isp->clk);
        
        isp->config.low_power = false;
        dev_info(isp->dev, "Waking from low power mode\n");
    }
    
    writel(reg_val, isp->base + REG_PMU_CTRL);
    
    /* 等待状态变化 */
    int timeout = 100;
    while (timeout--) {
        reg_val = readl(isp->base + REG_PMU_STATUS);
        if ((enable && (reg_val & BIT(0))) || 
            (!enable && !(reg_val & BIT(0)))) {
            break;
        }
        udelay(100);
    }
    
    return 0;
}
​
/**
 * @brief ISP中断处理函数
 * @param irq 中断号
 * @param data 设备指针
 * @return irqreturn_t
 * 
 * @details 处理:
 *          - 帧同步中断
 *          - 3DNR完成中断
 *          - 错误处理中断
 */
static irqreturn_t ssr305_isp_isr(int irq, void *data)
{
    struct ssr305_isp_dev *isp = data;
    uint32_t int_status;
    
    /* 读取中断状态 */
    int_status = readl(isp->base + REG_ISP_INT_STATUS);
    
    /* 帧同步中断 */
    if (int_status & BIT(0)) {
        isp->stats.frame_count++;
        
        /* 计算实时帧率 */
        static uint64_t last_time;
        static uint32_t frame_counter;
        uint64_t now = ktime_get_ns();
        
        frame_counter++;
        if (now - last_time > NSEC_PER_SEC) {
            isp->stats.current_fps = frame_counter;
            frame_counter = 0;
            last_time = now;
        }
    }
    
    /* 3DNR完成中断 */
    if (int_status & BIT(1)) {
        /* 降噪处理完成 */
    }
    
    /* 错误中断 */
    if (int_status & BIT(4)) {
        dev_err(isp->dev, "ISP error detected\n");
        isp->stats.dropped_count++;
    }
    
    /* 清除中断 */
    writel(int_status, isp->base + REG_ISP_INT_STATUS);
    
    return IRQ_HANDLED;
}
​
/* V4L2控制定义 */
static const struct v4l2_ctrl_ops ssr305_isp_ctrl_ops = {
    .s_ctrl = ssr305_isp_s_ctrl,
};
​
/**
 * @brief 注册ISP设备
 * @param pdev 平台设备指针
 * @return int
 */
static int ssr305_isp_probe(struct platform_device *pdev)
{
    struct ssr305_isp_dev *isp;
    struct resource *res;
    int ret;
    
    /* 分配设备结构体 */
    isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL);
    if (!isp) {
        return -ENOMEM;
    }
    
    isp->dev = &pdev->dev;
    
    /* 获取寄存器资源 */
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    isp->base = devm_ioremap_resource(&pdev->dev, res);
    if (IS_ERR(isp->base)) {
        return PTR_ERR(isp->base);
    }
    
    /* 获取时钟 */
    isp->clk = devm_clk_get(&pdev->dev, "isp");
    if (IS_ERR(isp->clk)) {
        dev_err(&pdev->dev, "Failed to get ISP clock\n");
        return PTR_ERR(isp->clk);
    }
    
    /* 使能时钟 */
    clk_prepare_enable(isp->clk);
    
    /* 注册V4L2子设备 */
    v4l2_subdev_init(&isp->subdev, &ssr305_isp_subdev_ops);
    isp->subdev.owner = THIS_MODULE;
    snprintf(isp->subdev.name, sizeof(isp->subdev.name), "ssr305-isp");
    
    /* 注册控制句柄 */
    v4l2_ctrl_handler_init(&isp->ctrl_handler, 5);
    v4l2_ctrl_new_std(&isp->ctrl_handler, &ssr305_isp_ctrl_ops,
                      V4L2_CID_3DNR_STRENGTH, 0, 255, 1, 128);
    isp->subdev.ctrl_handler = &isp->ctrl_handler;
    
    /* 注册中断 */
    ret = devm_request_irq(&pdev->dev, platform_get_irq(pdev, 0),
                           ssr305_isp_isr, 0, "ssr305-isp", isp);
    if (ret) {
        dev_err(&pdev->dev, "Failed to request IRQ\n");
        return ret;
    }
    
    platform_set_drvdata(pdev, isp);
    
    dev_info(&pdev->dev, "SSR305 ISP initialized successfully\n");
    
    return 0;
}
​
module_init(ssr305_isp_init);
module_exit(ssr305_isp_exit);
​
MODULE_LICENSE("GPL");
MODULE_AUTHOR("SigmaStar/OpenIPC");
MODULE_DESCRIPTION("SSR305 ISP Driver");

第五部分:OpenIPC工具链代码分析

1. 文件:tools/ipctool/ipctool.c

/**
 * @file ipctool.c
 * @brief IPC硬件检测工具
 * @author OpenIPC Team
 * @version 2.0.0
 * 
 * @details 多功能硬件检测工具,支持:
 *          - SoC型号识别
 *          - 传感器检测
 *          - 内存大小检测
 *          - 网络接口信息
 *          - 温度读取
 *          
 * @note 这是OpenIPC固件中最重要的诊断工具
 */
​
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
​
/**
 * @defgroup Soc_Detection SoC检测模块
 * @{
 */
​
/**
 * @struct soc_info
 * @brief SoC信息结构体
 */
typedef struct {
    char family[32];        /**< 芯片系列:Hi3516, SSC335等 */
    char model[32];         /**< 具体型号 */
    uint32_t revision;      /**< 版本号 */
    uint32_t cpu_freq;      /**< CPU频率,单位:MHz */
    uint32_t cores;         /**< CPU核心数 */
    uint64_t total_mem;     /**< 总内存,单位:字节 */
    uint64_t free_mem;      /**< 空闲内存,单位:字节 */
    uint32_t temperature;   /**< 芯片温度,单位:0.1°C */
} soc_info_t;
​
/**
 * @brief 读取CPU信息
 * @param info SoC信息输出指针
 * @return int 成功返回0
 * 
 * @details 通过读取/proc/cpuinfo解析SoC信息
 *          示例输出:
 *          Processor: ARMv7 Processor rev 1 (v7l)
 *          Hardware: Hi3516EV200
 *          Revision: 0000
 */
static int read_cpu_info(soc_info_t *info)
{
    FILE *fp;
    char line[256];
    char *ptr;
    
    fp = fopen("/proc/cpuinfo", "r");
    if (!fp) {
        return -1;
    }
    
    while (fgets(line, sizeof(line), fp)) {
        if (strstr(line, "Hardware")) {
            ptr = strchr(line, ':');
            if (ptr) {
                ptr += 2;  /* 跳过": " */
                strncpy(info->family, ptr, sizeof(info->family) - 1);
                /* 去除换行符 */
                info->family[strcspn(info->family, "\n")] = 0;
            }
        }
        
        if (strstr(line, "Revision")) {
            ptr = strchr(line, ':');
            if (ptr) {
                info->revision = strtoul(ptr + 2, NULL, 16);
            }
        }
        
        if (strstr(line, "BogoMIPS")) {
            /* 估算CPU频率 */
            ptr = strchr(line, ':');
            if (ptr) {
                float bogomips = atof(ptr + 2);
                info->cpu_freq = (uint32_t)(bogomips / 2.0);
            }
        }
        
        if (strstr(line, "processor")) {
            info->cores++;
        }
    }
    
    fclose(fp);
    return 0;
}
​
/**
 * @brief 读取内存信息
 * @param info SoC信息输出指针
 * @return int 成功返回0
 * 
 * @details 解析/proc/meminfo获取内存大小
 *          单位转换:kB -> bytes
 */
static int read_mem_info(soc_info_t *info)
{
    FILE *fp;
    char line[256];
    
    fp = fopen("/proc/meminfo", "r");
    if (!fp) {
        return -1;
    }
    
    while (fgets(line, sizeof(line), fp)) {
        if (strncmp(line, "MemTotal:", 9) == 0) {
            unsigned long kb;
            sscanf(line, "MemTotal: %lu kB", &kb);
            info->total_mem = kb * 1024;
        }
        
        if (strncmp(line, "MemFree:", 8) == 0) {
            unsigned long kb;
            sscanf(line, "MemFree: %lu kB", &kb);
            info->free_mem = kb * 1024;
        }
    }
    
    fclose(fp);
    return 0;
}
​
/**
 * @brief 读取芯片温度
 * @param info SoC信息输出指针
 * @return int 成功返回0
 * 
 * @details 尝试多个可能的温度传感器路径:
 *          - /sys/class/thermal/thermal_zone0/temp
 *          - /proc/jz/thermal
 *          - /sys/devices/virtual/thermal/thermal_zone0/temp
 */
static int read_temperature(soc_info_t *info)
{
    FILE *fp;
    const char *paths[] = {
        "/sys/class/thermal/thermal_zone0/temp",
        "/sys/class/thermal/thermal_zone1/temp",
        "/proc/jz/thermal",
        NULL
    };
    
    for (int i = 0; paths[i]; i++) {
        fp = fopen(paths[i], "r");
        if (fp) {
            int temp;
            if (fscanf(fp, "%d", &temp) == 1) {
                /* 处理不同格式:
                 * 有些是整数度:45
                 * 有些是千分之一度:45000
                 */
                if (temp > 1000) {
                    info->temperature = temp / 100;  /* 转成0.1°C */
                } else {
                    info->temperature = temp * 10;
                }
                fclose(fp);
                return 0;
            }
            fclose(fp);
        }
    }
    
    return -1;
}
​
/** @} */
​
/**
 * @defgroup Sensor_Detection 传感器检测模块
 * @{
 */
​
/**
 * @struct sensor_info
 * @brief 图像传感器信息
 */
typedef struct {
    char name[32];          /**< 传感器型号:IMX335, SC2235等 */
    uint8_t i2c_addr;       /**< I2C地址 */
    uint32_t width;         /**< 最大宽度 */
    uint32_t height;        /**< 最大高度 */
    uint32_t fps;           /**< 最大帧率 */
    char bus[16];           /**< I2C总线 */
} sensor_info_t;
​
/**
 * @brief 传感器ID表
 * 
 * @details 常见传感器I2C ID寄存器及预期值
 */
static const struct {
    const char *name;
    uint8_t addr;
    uint8_t id_reg;
    uint16_t id_value;
} sensor_ids[] = {
    {"IMX335", 0x1A, 0x02, 0x0335},  /* Sony 5MP */
    {"IMX307", 0x1A, 0x00, 0x0307},  /* Sony 2MP */
    {"IMX327", 0x1A, 0x00, 0x0327},  /* Sony 2MP */
    {"SC2235", 0x30, 0x31, 0x2235},  /* SmartSens 2MP */
    {"SC3235", 0x30, 0x31, 0x3235},  /* SmartSens 5MP */
    {"GC2053", 0x37, 0x03, 0x2053},  /* GalaxyCore 2MP */
    {NULL, 0, 0, 0}
};
​
/**
 * @brief 检测图像传感器
 * @param sensor 传感器信息输出指针
 * @return int 成功返回0,失败返回-1
 * 
 * @details I2C通信协议:
 *          1. 打开I2C总线设备
 *          2. 设置从设备地址
 *          3. 发送寄存器地址
 *          4. 读取16位ID值
 */
static int detect_sensor(sensor_info_t *sensor)
{
    int file;
    char filename[32];
    uint8_t reg;
    uint16_t value;
    struct i2c_msg msgs[2];
    struct i2c_rdwr_ioctl_data msgset;
    
    /* 尝试多个I2C总线 */
    const char *buses[] = {"/dev/i2c-0", "/dev/i2c-1", "/dev/i2c-2", NULL};
    
    for (int b = 0; buses[b]; b++) {
        file = open(buses[b], O_RDWR);
        if (file < 0) continue;
        
        /* 遍历已知传感器 */
        for (int i = 0; sensor_ids[i].name; i++) {
            /* 设置I2C从设备地址 */
            if (ioctl(file, I2C_SLAVE, sensor_ids[i].addr) < 0) {
                continue;
            }
            
            /* 读取ID寄存器 */
            reg = sensor_ids[i].id_reg;
            
            if (sensor_ids[i].id_value > 0xFF) {
                /* 16位ID:需要读两个字节 */
                uint8_t buf[2];
                struct i2c_msg rdmsg = {
                    .addr = sensor_ids[i].addr,
                    .flags = I2C_M_RD,
                    .len = 2,
                    .buf = buf
                };
                
                if (write(file, &reg, 1) != 1) continue;
                
                if (read(file, buf, 2) != 2) continue;
                
                value = (buf[0] << 8) | buf[1];
            } else {
                /* 8位ID */
                uint8_t val;
                if (write(file, &reg, 1) != 1) continue;
                if (read(file, &val, 1) != 1) continue;
                value = val;
            }
            
            /* 检查是否匹配 */
            if (value == sensor_ids[i].id_value) {
                strcpy(sensor->name, sensor_ids[i].name);
                sensor->i2c_addr = sensor_ids[i].addr;
                strcpy(sensor->bus, buses[b] + 9);  /* 去掉"/dev/i2c-" */
                
                close(file);
                return 0;
            }
        }
        
        close(file);
    }
    
    return -1;
}
​
/** @} */
​
/**
 * @brief 主函数
 * @param argc 参数个数
 * @param argv 参数数组
 * @return int
 * 
 * @details 命令行选项:
 *          ipctool -a          显示所有信息
 *          ipctool -s          显示SoC信息
 *          ipctool -c          显示传感器信息
 *          ipctool -n          显示网络信息
 *          ipctool -t          显示温度
 *          ipctool -h          显示帮助
 */
int main(int argc, char **argv)
{
    int opt;
    int show_all = 1;  /* 默认显示所有 */
    int show_soc = 0;
    int show_sensor = 0;
    int show_net = 0;
    int show_temp = 0;
    
    while ((opt = getopt(argc, argv, "ascnth")) != -1) {
        switch (opt) {
            case 'a':
                show_all = 1;
                break;
            case 's':
                show_soc = 1;
                show_all = 0;
                break;
            case 'c':
                show_sensor = 1;
                show_all = 0;
                break;
            case 'n':
                show_net = 1;
                show_all = 0;
                break;
            case 't':
                show_temp = 1;
                show_all = 0;
                break;
            case 'h':
                printf("Usage: %s [options]\n", argv[0]);
                printf("Options:\n");
                printf("  -a    Show all information\n");
                printf("  -s    Show SoC information\n");
                printf("  -c    Show sensor information\n");
                printf("  -n    Show network information\n");
                printf("  -t    Show temperature\n");
                printf("  -h    Show this help\n");
                return 0;
        }
    }
    
    /* 收集信息 */
    soc_info_t soc = {0};
    sensor_info_t sensor = {0};
    
    if (show_all || show_soc || show_temp) {
        read_cpu_info(&soc);
        read_mem_info(&soc);
        read_temperature(&soc);
    }
    
    if (show_all || show_sensor) {
        detect_sensor(&sensor);
    }
    
    /* 显示信息 */
    if (show_all || show_soc) {
        printf("========== SoC Information ==========\n");
        printf("Family:     %s\n", soc.family);
        printf("Revision:   0x%04x\n", soc.revision);
        printf("CPU:        %u MHz, %u core(s)\n", soc.cpu_freq, soc.cores);
        printf("Memory:     %.2f MB total, %.2f MB free\n",
               soc.total_mem / (1024.0 * 1024.0),
               soc.free_mem / (1024.0 * 1024.0));
    }
    
    if (show_all || show_sensor) {
        printf("========== Sensor Information ==========\n");
        if (sensor.name[0]) {
            printf("Model:      %s\n", sensor.name);
            printf("I2C:        %s @ 0x%02x\n", sensor.bus, sensor.i2c_addr);
        } else {
            printf("No sensor detected\n");
        }
    }
    
    if (show_all || show_temp) {
        printf("========== Temperature ==========\n");
        if (soc.temperature) {
            printf("SoC:        %d.%d°C\n", 
                   soc.temperature / 10, soc.temperature % 10);
        } else {
            printf("Not available\n");
        }
    }
    
    return 0;
}

第六部分:YAML配置管理分析

1. 文件:tools/yaml-cli/yaml-cli.c

/**
 * @file yaml-cli.c
 * @brief YAML配置文件命令行工具
 * @author OpenIPC Team
 * @version 1.5.0
 * 
 * @details 用于读写OpenIPC YAML配置文件的工具
 *          支持:
 *          - 读取配置值
 *          - 写入配置值
 *          - 备份和恢复
 *          - JSON格式转换
 *          
 * @note 主要操作 /etc/majestic.yaml 配置文件
 */
​
#include <yaml.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
​
/**
 * @defgroup YAML_Paths YAML路径语法
 * @{
 * 
 * @details 使用点号分隔的路径语法:
 *          video0.width           - 获取视频宽度
 *          video0.fps             - 获取帧率
 *          osd.timestamp.enable   - OSD时间戳开关
 *          network.ip             - IP地址
 * 
 * 支持通配符:
 *          video*.width           - 所有视频流的宽度
 * 
 * 支持数组索引:
 *          streams.0.enable       - 第一个码流
 * @}
 */
​
/**
 * @struct yaml_node_path
 * @brief YAML路径解析结果
 */
typedef struct {
    char **keys;        /**< 路径各段数组 */
    int depth;          /**< 路径深度 */
    int is_array;       /**< 是否数组访问 */
    int array_index;    /**< 数组索引 */
} yaml_path_t;
​
/**
 * @brief 解析YAML路径字符串
 * @param path_str 路径字符串,如"video0.width"
 * @param path 解析结果输出
 * @return int 成功返回0
 * 
 * @example
 * "video0.width" -> keys=["video0", "width"], depth=2
 * "osd.timestamp.enable" -> keys=["osd", "timestamp", "enable"], depth=3
 */
static int parse_yaml_path(const char *path_str, yaml_path_t *path)
{
    char *str = strdup(path_str);
    char *token;
    char *saveptr;
    int count = 0;
    
    /* 分配最大深度 */
    path->keys = malloc(10 * sizeof(char*));
    
    /* 分割路径 */
    token = strtok_r(str, ".", &saveptr);
    while (token && count < 10) {
        /* 检查是否为数组访问 */
        char *bracket = strchr(token, '[');
        if (bracket) {
            *bracket = '\0';
            path->array_index = atoi(bracket + 1);
            path->is_array = 1;
        }
        
        path->keys[count] = strdup(token);
        count++;
        token = strtok_r(NULL, ".", &saveptr);
    }
    
    path->depth = count;
    free(str);
    return 0;
}
​
/**
 * @brief 递归查找YAML节点
 * @param document YAML文档
 * @param path 路径
 * @param level 当前层级
 * @return yaml_node_t* 找到的节点,NULL表示未找到
 */
static yaml_node_t* find_yaml_node(yaml_document_t *document, 
                                   yaml_path_t *path, int level)
{
    yaml_node_t *node = yaml_document_get_root_node(document);
    
    for (int i = 0; i < level; i++) {
        if (!node) return NULL;
        
        switch (node->type) {
            case YAML_MAPPING_NODE:
                /* 在映射中查找键 */
                for (yaml_node_pair_t *pair = node->data.mapping.pairs.start;
                     pair < node->data.mapping.pairs.top;
                     pair++) {
                    
                    yaml_node_t *key = yaml_document_get_node(document, pair->key);
                    if (key && key->type == YAML_SCALAR_NODE) {
                        if (strcmp((char*)key->data.scalar.value, 
                                   path->keys[i]) == 0) {
                            node = yaml_document_get_node(document, pair->value);
                            break;
                        }
                    }
                }
                break;
                
            case YAML_SEQUENCE_NODE:
                /* 序列节点,使用索引 */
                if (path->is_array && i == level - 1) {
                    int idx = path->array_index;
                    if (idx < node->data.sequence.items.top - 
                               node->data.sequence.items.start) {
                        node = yaml_document_get_node(document, 
                                    node->data.sequence.items.start[idx]);
                    }
                }
                break;
                
            default:
                return NULL;
        }
    }
    
    return node;
}
​
/**
 * @brief 读取配置值
 * @param path 配置路径
 * @return int 成功返回0
 */
static int cmd_get(const char *path)
{
    FILE *fh = fopen("/etc/majestic.yaml", "rb");
    if (!fh) {
        perror("Failed to open config file");
        return -1;
    }
    
    yaml_parser_t parser;
    yaml_document_t document;
    
    yaml_parser_initialize(&parser);
    yaml_parser_set_input_file(&parser, fh);
    
    if (!yaml_parser_load(&parser, &document)) {
        fprintf(stderr, "Failed to parse YAML\n");
        fclose(fh);
        return -1;
    }
    
    /* 解析路径并查找节点 */
    yaml_path_t ypath;
    parse_yaml_path(path, &ypath);
    
    yaml_node_t *node = find_yaml_node(&document, &ypath, ypath.depth);
    
    if (node && node->type == YAML_SCALAR_NODE) {
        printf("%s\n", node->data.scalar.value);
    } else {
        fprintf(stderr, "Path not found or not a scalar\n");
    }
    
    /* 清理 */
    yaml_document_delete(&document);
    yaml_parser_delete(&parser);
    fclose(fh);
    
    return 0;
}
​
/**
 * @brief 设置配置值
 * @param path 配置路径
 * @param value 要设置的值
 * @return int 成功返回0
 */
static int cmd_set(const char *path, const char *value)
{
    /* 先读取整个文档 */
    FILE *fh = fopen("/etc/majestic.yaml", "rb");
    if (!fh) return -1;
    
    yaml_parser_t parser;
    yaml_document_t document;
    
    yaml_parser_initialize(&parser);
    yaml_parser_set_input_file(&parser, fh);
    
    if (!yaml_parser_load(&parser, &document)) {
        fclose(fh);
        return -1;
    }
    fclose(fh);
    
    /* 查找并修改节点 */
    yaml_path_t ypath;
    parse_yaml_path(path, &ypath);
    
    yaml_node_t *node = find_yaml_node(&document, &ypath, ypath.depth);
    
    if (node && node->type == YAML_SCALAR_NODE) {
        /* 更新现有节点 */
        free(node->data.scalar.value);
        node->data.scalar.value = strdup(value);
        node->data.scalar.length = strlen(value);
    } else {
        /* 路径不存在,需要创建 */
        fprintf(stderr, "Creating new paths not yet supported\n");
    }
    
    /* 写回文件 */
    FILE *out = fopen("/etc/majestic.yaml", "wb");
    if (!out) return -1;
    
    yaml_emitter_t emitter;
    yaml_emitter_initialize(&emitter);
    yaml_emitter_set_output_file(&emitter, out);
    yaml_emitter_open(&emitter);
    yaml_emitter_dump(&emitter, &document);
    yaml_emitter_close(&emitter);
    yaml_emitter_delete(&emitter);
    
    fclose(out);
    
    /* 清理 */
    yaml_document_delete(&document);
    yaml_parser_delete(&parser);
    
    return 0;
}
​
/**
 * @brief 主函数
 * @param argc 参数个数
 * @param argv 参数数组
 * @return int
 * 
 * @example
 * yaml-cli -g video0.width          # 获取视频宽度
 * yaml-cli -s video0.width 1920     # 设置视频宽度
 * yaml-cli -d                        # 显示所有配置
 * yaml-cli -b /backup.yaml           # 备份配置
 */
int main(int argc, char **argv)
{
    int opt;
    char *get_path = NULL;
    char *set_path = NULL;
    char *set_value = NULL;
    int dump = 0;
    char *backup = NULL;
    
    while ((opt = getopt(argc, argv, "g:s:b:d")) != -1) {
        switch (opt) {
            case 'g':
                get_path = optarg;
                break;
            case 's':
                set_path = optarg;
                if (optind < argc && argv[optind][0] != '-') {
                    set_value = argv[optind++];
                }
                break;
            case 'b':
                backup = optarg;
                break;
            case 'd':
                dump = 1;
                break;
        }
    }
    
    if (get_path) {
        return cmd_get(get_path);
    }
    
    if (set_path && set_value) {
        return cmd_set(set_path, set_value);
    }
    
    if (backup) {
        /* 备份配置 */
        char cmd[256];
        snprintf(cmd, sizeof(cmd), "cp /etc/majestic.yaml %s", backup);
        return system(cmd);
    }
    
    if (dump) {
        /* 显示所有配置 */
        FILE *fp = fopen("/etc/majestic.yaml", "rb");
        if (fp) {
            char buf[1024];
            size_t n;
            while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
                fwrite(buf, 1, n, stdout);
            }
            fclose(fp);
        }
    }
    
    return 0;
}

第七部分:数据处理流水线对比分析

1. 数据处理单元对比表

处理阶段 数据格式 典型大小(1080p) 处理单元 延迟 关键代码位置
RAW采集 Bayer RAW 1920x1080x14/8 = 3.6MB 33ms (30fps) drivers/media/i2c/
ISP处理 RGB/NV12 1920x1080x1.5 = 3.1MB 16ms ssr305_isp.c
编码 H.264/H.265 50-200KB (I帧) / 5-20KB (P帧) 帧/Slice 10ms h265_encoder.c
RTP打包 RTP包 1400字节/包 1ms rtsp_server.c
存储 MP4/TS 1小时≈1-2GB 文件 - recorder.c

2. 内存带宽计算

/**
 * @brief 计算不同格式的内存带宽需求
 * 
 * @note 以1080p@30fps为例:
 * - RAW数据: 1920*1080*14/8 * 30 = 108.9 MB/s
 * - NV12数据: 1920*1080*12/8 * 30 = 93.3 MB/s
 * - RGB24数据: 1920*1080*3 * 30 = 186.6 MB/s
 * 
 * 考虑DDR带宽限制,通常选择NV12作为处理格式
 */
static void calculate_bandwidth(void)
{
    const int width = 1920;
    const int height = 1080;
    const int fps = 30;
    
    /* 原始Bayer RAW (14bit) */
    uint64_t raw_bps = (uint64_t)width * height * 14 * fps / 8;
    
    /* NV12 (YUV420) */
    uint64_t nv12_bps = (uint64_t)width * height * 12 * fps / 8;
    
    /* RGB888 */
    uint64_t rgb_bps = (uint64_t)width * height * 24 * fps / 8;
    
    printf("Memory Bandwidth Requirements:\n");
    printf("  RAW:   %.2f MB/s\n", raw_bps / (1024.0 * 1024.0));
    printf("  NV12:  %.2f MB/s\n", nv12_bps / (1024.0 * 1024.0));
    printf("  RGB:   %.2f MB/s\n", rgb_bps / (1024.0 * 1024.0));
}

3. 码率控制算法对比

/**
 * @file majestic/src/encoder/rate_control.c
 * @brief 码率控制算法实现
 */
​
/**
 * @enum rc_mode_t
 * @brief 码率控制模式
 */
typedef enum {
    RC_MODE_CBR,    /**< 恒定码率:码率波动小,适合直播 */
    RC_MODE_VBR,    /**< 可变码率:画质稳定,适合存储 */
    RC_MODE_ABR,    /**< 平均码率:平衡模式 */
    RC_MODE_CQP     /**< 恒定质量:QP固定,质量恒定 */
} rc_mode_t;
​
/**
 * @struct rc_params_t
 * @brief 码率控制参数
 */
typedef struct {
    rc_mode_t mode;      /**< 控制模式 */
    uint32_t target_kbps; /**< 目标码率,单位kbps */
    uint32_t max_kbps;    /**< 最大码率 */
    uint32_t min_kbps;    /**< 最小码率 */
    uint8_t init_qp;      /**< 初始QP值 0-51 */
    uint8_t min_qp;       /**< 最小QP */
    uint8_t max_qp;       /**< 最大QP */
    
    /* 场景检测参数 */
    uint32_t scene_change_threshold;  /**< 场景切换阈值 */
    uint8_t scene_change_qp_delta;    /**< 场景切换QP调整 */
    
    /* GOP层控制 */
    uint8_t gop_size;      /**< GOP大小 */
    uint8_t intra_period;  /**< I帧间隔 */
    uint8_t idr_period;    /**< IDR帧间隔 */
} rc_params_t;
​
/**
 * @brief CBR码率控制器
 * 
 * @details 使用PID反馈控制算法:
 *          QP_delta = Kp*error + Ki*integral + Kd*derivative
 *          error = target_bitrate - actual_bitrate
 */
static int cbr_rate_control(encoder_t *enc, frame_stats_t *stats)
{
    static int64_t integral = 0;
    static int64_t prev_error = 0;
    
    const int Kp = 10;   /* 比例系数 */
    const int Ki = 2;    /* 积分系数 */
    const int Kd = 5;    /* 微分系数 */
    
    /* 计算当前码率 */
    int64_t current_bitrate = calculate_bitrate(enc);
    int64_t error = enc->target_bitrate - current_bitrate;
    
    /* 积分项限制,防止积分饱和 */
    integral += error;
    if (integral > 1000) integral = 1000;
    if (integral < -1000) integral = -1000;
    
    /* 微分项 */
    int64_t derivative = error - prev_error;
    
    /* PID计算QP调整量 */
    int qp_delta = (Kp * error + Ki * integral + Kd * derivative) / 100;
    
    /* 限制QP调整范围 */
    if (qp_delta > 6) qp_delta = 6;
    if (qp_delta < -6) qp_delta = -6;
    
    /* 更新QP值 */
    uint8_t new_qp = enc->current_qp + qp_delta;
    if (new_qp < enc->min_qp) new_qp = enc->min_qp;
    if (new_qp > enc->max_qp) new_qp = enc->max_qp;
    
    prev_error = error;
    
    return new_qp;
}
​
/**
 * @brief VBR码率控制器
 * 
 * @details 基于场景复杂度调整:
 *          QP = base_qp + complexity_factor * scene_factor
 *          复杂度使用SAD(绝对差值和)衡量
 */
static int vbr_rate_control(encoder_t *enc, frame_stats_t *stats)
{
    /* 计算帧复杂度(使用SAD或方差) */
    uint32_t complexity = stats->sad_value;
    
    /* 归一化复杂度 */
    float complexity_factor = (float)complexity / enc->avg_complexity;
    
    /* 根据复杂度调整QP */
    uint8_t base_qp = enc->target_qp;
    int qp_adjust = (int)((complexity_factor - 1.0) * 5);
    
    /* 场景切换处理 */
    if (stats->is_scene_change) {
        qp_adjust += enc->scene_change_qp_delta;
    }
    
    uint8_t new_qp = base_qp + qp_adjust;
    
    /* 限制QP范围 */
    if (new_qp < enc->min_qp) new_qp = enc->min_qp;
    if (new_qp > enc->max_qp) new_qp = enc->max_qp;
    
    return new_qp;
}

第八部分:性能优化关键点

1. 缓存一致性管理

/**
 * @file arch/arm/mm/cache-v7.c
 * @brief ARMv7缓存操作
 */
​
/**
 * @brief DMA缓冲区缓存维护
 * @param addr 缓冲区地址
 * @param size 缓冲区大小
 * @param dir DMA方向
 * 
 * @note 关键:确保CPU和DMA看到的是一致的数据
 *       在以下情况必须调用:
 *       - CPU写入数据给DMA处理前
 *       - DMA完成后CPU读取数据前
 */
static void dma_cache_maint(const void *addr, size_t size, int dir)
{
    unsigned long start = (unsigned long)addr;
    unsigned long end = start + size;
    
    switch (dir) {
        case DMA_FROM_DEVICE:
            /* 数据从设备到CPU:需要使缓存失效 */
            v7_dma_inv_range(start, end);
            break;
            
        case DMA_TO_DEVICE:
            /* 数据从CPU到设备:需要刷写缓存 */
            v7_dma_clean_range(start, end);
            break;
            
        case DMA_BIDIRECTIONAL:
            /* 双向:刷写并使失效 */
            v7_dma_flush_range(start, end);
            break;
    }
    
    dsb();  /* 数据同步屏障,确保操作完成 */
}

2. 零拷贝技术实现

/**
 * @file majestic/src/streaming/zero_copy.c
 * @brief 零拷贝流处理
 */
​
/**
 * @brief 使用ION内存实现零拷贝
 * 
 * @details 流程:
 *          1. ION分配物理连续内存
 *          2. VPU/VENC直接访问物理地址
 *          3. 通过DMABUF共享给用户态
 *          4. 用户态mmap直接访问
 */
static int init_zero_copy_pipeline(encoder_t *enc)
{
    struct ion_allocation_data alloc_data = {
        .len = enc->buffer_size,
        .align = 4096,
        .flags = ION_FLAG_CACHED,
        .heap_id_mask = 1 << ION_HEAP_TYPE_CARVEOUT,
    };
    
    /* 分配ION缓冲区 */
    int ion_fd = open("/dev/ion", O_RDWR);
    if (ion_fd < 0) return -1;
    
    if (ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data) < 0) {
        close(ion_fd);
        return -1;
    }
    
    /* 获取DMA缓冲区句柄 */
    struct ion_fd_data fd_data = {
        .handle = alloc_data.handle,
    };
    
    if (ioctl(ion_fd, ION_IOC_SHARE, &fd_data) < 0) {
        close(ion_fd);
        return -1;
    }
    
    /* 用户态映射 */
    void *vaddr = mmap(NULL, enc->buffer_size, 
                       PROT_READ | PROT_WRITE, 
                       MAP_SHARED, fd_data.fd, 0);
    
    /* 传递物理地址给硬件 */
    struct ion_custom_data custom_data = {
        .cmd = ION_IOC_PHYS_ADDR,
        .arg = (unsigned long)&phys_data,
    };
    ioctl(ion_fd, ION_IOC_CUSTOM, &custom_data);
    
    enc->hw_addr = phys_data.phys;
    enc->vaddr = vaddr;
    
    return 0;
}

第九部分:AI推理框架

1. 文件:majestic-plugins/plugins/motion_detection/md_ai.c

/**
 * @file md_ai.c
 * @brief AI运动检测插件
 * @author OpenIPC Team
 * @version 1.0.0
 * 
 * @details 基于NPU的运动检测实现
 *          使用轻量级CNN模型,8bit量化
 *          输入:320x240 NV12
 *          输出:运动区域bbox + 置信度
 */
​
#include <npu.h>
​
/**
 * @struct ai_model_t
 * @brief AI模型信息
 */
typedef struct {
    const char *name;        /**< 模型名称 */
    uint8_t *model_data;     /**< 模型数据 */
    size_t model_size;       /**< 模型大小 */
    
    struct {
        uint32_t width;      /**< 输入宽度 */
        uint32_t height;     /**< 输入高度 */
        uint32_t channels;   /**< 输入通道 */
        uint32_t format;     /**< 输入格式 */
    } input;
    
    struct {
        uint32_t num_outputs;/**< 输出数量 */
        uint32_t *sizes;     /**< 输出大小数组 */
    } output;
    
    uint32_t npu_freq;       /**< NPU运行频率 */
    uint32_t latency;        /**< 推理延迟,单位us */
} ai_model_t;
​
/**
 * @brief 初始化NPU推理引擎
 * @param model_path 模型文件路径
 * @return void* 引擎句柄
 */
void* ai_engine_init(const char *model_path)
{
    npu_session_t *session = malloc(sizeof(npu_session_t));
    
    /* 加载模型 */
    FILE *fp = fopen(model_path, "rb");
    fseek(fp, 0, SEEK_END);
    size_t model_size = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    
    uint8_t *model_data = malloc(model_size);
    fread(model_data, 1, model_size, fp);
    fclose(fp);
    
    /* 初始化NPU */
    npu_init_params_t params = {
        .model_data = model_data,
        .model_size = model_size,
        .npu_freq = 500,  /* 500MHz */
        .core = 0,
    };
    
    npu_init(session, &params);
    
    /* 预热 */
    for (int i = 0; i < 3; i++) {
        npu_run(session, NULL, NULL);
    }
    
    return session;
}
​
/**
 * @brief 执行AI推理
 * @param session 引擎句柄
 * @param frame 输入帧
 * @param results 检测结果输出
 * @return int 检测到的目标数量
 */
int ai_engine_infer(void *session, video_frame_t *frame, detection_t *results)
{
    npu_session_t *sess = (npu_session_t*)session;
    
    /* 预处理:缩放+格式转换 */
    uint8_t *input_data = preprocess(frame, sess->input_width, sess->input_height);
    
    /* 执行推理 */
    uint64_t start = get_timestamp_us();
    npu_buffer_t output;
    npu_run(sess, input_data, &output);
    uint64_t end = get_timestamp_us();
    
    /* 记录延迟 */
    sess->last_latency = end - start;
    
    /* 后处理:解析输出 */
    int num_detections = postprocess(&output, results, MAX_DETECTIONS);
    
    free(input_data);
    
    return num_detections;
}

总结:代码结构关键点

组件 关键文件 核心数据结构 数据流单位 性能关键点
ISP驱动 ssr305_isp.c ssr305_isp_dev 帧 (3-10MB/s) 3DNR/WDR硬件加速
视频编码 h265_encoder.c h265_config_t 帧/NALU (5-200KB) 硬件VPU利用
流媒体 rtsp_server.c rtsp_session_t RTP包 (1400B) epoll并发
配置管理 yaml-cli.c yaml_path_t YAML节点 运行时重载
硬件检测 ipctool.c soc_info_t 系统信息 多源探测
AI推理 md_ai.c ai_model_t 检测框 NPU量化加速
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐