v4l2驱动开发

V4L2驱动开发完全指南

第1章 V4L2框架概述

1.1 V4L2历史与发展

**V4L2**(Video for Linux Two)是Linux内核中视频设备的标准API框架。从Linux 2.5.46内核开始引入,逐步替代了旧的V4L接口。

**发展历程**:

  • 1998年:V4L首次发布

  • 2002年:V4L2正式成为内核标准

  • 2010年:引入V4L2控制框架

  • 2012年:引入媒体控制器框架

  • 2015年:V4L2异步框架

1.2 V4L2系统架构

1.2.1 用户空间接口

```

用户空间应用程序

├── 应用程序层 (v4l2-ctl, gstreamer, ffmpeg)

├── V4L2库 (libv4l2)

└── 系统调用接口

```

1.2.2 内核空间架构

```

内核空间

├── 字符设备层 (V4L2字符设备)

│ ├── /dev/videoX

│ ├── /dev/v4l-subdevX

│ └── /dev/mediaX

├── V4L2核心层

│ ├── v4l2-device.c - 设备管理

│ ├── v4l2-ioctl.c - IOCTL处理

│ ├── v4l2-ctrls.c - 控制框架

│ ├── v4l2-fh.c - 文件句柄管理

│ └── v4l2-event.c - 事件通知

├── 视频缓冲区核心 (videobuf2)

│ ├── videobuf2-core.c

│ ├── videobuf2-v4l2.c

│ ├── videobuf2-memops.c

│ └── 内存后端 (dma-contig, dma-sg)

├── 子设备框架 (v4l2-subdev)

│ ├── 子设备注册

│ ├── 子设备操作

│ └── 内部接口

├── 媒体控制器框架

│ ├── 媒体设备

│ ├── 实体与链接

│ └── 拓扑管理

└── 平台特定驱动

├── 传感器驱动

├── ISP驱动

├── 编解码器驱动

└── 显示驱动

```

1.3 V4L2核心数据结构

1.3.1 struct v4l2_device

```c

struct v4l2_device {

struct device *dev; // 关联的设备

const char *name; // 设备名称

struct list_head subdevs; // 子设备链表

spinlock_t lock; // 锁

struct v4l2_ctrl_handler *ctrl_handler;

struct media_device *mdev; // 媒体设备

};

```

1.3.2 struct video_device

```c

struct video_device {

struct device dev; // 设备结构

struct cdev *cdev; // 字符设备

struct v4l2_device *v4l2_dev; // V4L2设备

const struct v4l2_file_operations *fops;

struct v4l2_ioctl_ops *ioctl_ops;

struct vb2_queue *queue; // 视频缓冲区队列

struct media_entity entity; // 媒体实体

u32 device_caps; // 设备能力

int minor; // 次设备号

char name[32]; // 设备名称

};

```

1.3.3 struct v4l2_subdev

```c

struct v4l2_subdev {

struct media_entity entity; // 媒体实体

struct list_head list; // 链表

struct module *owner; // 模块所有者

struct v4l2_device *v4l2_dev; // 所属V4L2设备

const struct v4l2_subdev_ops *ops;

struct v4l2_ctrl_handler *ctrl_handler;

char name[V4L2_SUBDEV_NAME_SIZE];

};

```

第2章 V4L2设备类型与能力

2.1 设备类型分类

2.1.1 捕获设备 (Capture)

```c

#define V4L2_CAP_VIDEO_CAPTURE 0x00000001

#define V4L2_CAP_VIDEO_CAPTURE_MPLANE 0x00001000

```

用于从摄像头、采集卡等设备捕获视频数据。

2.1.2 输出设备 (Output)

```c

#define V4L2_CAP_VIDEO_OUTPUT 0x00000002

#define V4L2_CAP_VIDEO_OUTPUT_MPLANE 0x00002000

```

用于视频输出到显示设备。

2.1.3 覆盖设备 (Overlay)

```c

#define V4L2_CAP_VIDEO_OVERLAY 0x00000004

```

用于视频覆盖显示。

2.1.4 视频空白缓冲设备 (VBI)

```c

#define V4L2_CAP_VBI_CAPTURE 0x00000010

#define V4L2_CAP_VBI_OUTPUT 0x00000020

```

用于VBI(垂直消隐间隔)数据。

2.1.5 切片设备 (Sliced VBI)

```c

#define V4L2_CAP_SLICED_VBI_CAPTURE 0x00000040

#define V4L2_CAP_SLICED_VBI_OUTPUT 0x00000080

```

切片VBI数据。

2.1.6 元数据设备 (Metadata)

```c

#define V4L2_CAP_META_CAPTURE 0x00080000

```

用于捕获元数据。

2.2 设备能力标志

2.2.1 流类型

```c

#define V4L2_CAP_STREAMING 0x04000000

#define V4L2_CAP_READWRITE 0x01000000

```

2.2.2 扩展能力

```c

#define V4L2_CAP_DEVICE_CAPS 0x80000000

#define V4L2_CAP_EXT_PIX_FORMAT 0x10000000

```

第3章 视频格式与像素格式

3.1 像素格式定义

3.1.1 常见RGB格式

```c

#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R', 'G', 'B', '1')

#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R', 'G', 'B', 'P')

#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3')

#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3')

#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R', 'G', 'B', '4')

#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4')

```

3.1.2 YUV格式

```c

// 打包YUV格式

#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y', 'U', 'Y', 'V')

#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U')

#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U', 'Y', 'V', 'Y')

#define V4L2_PIX_FMT_VYUY v4l2_fourcc('V', 'Y', 'U', 'Y')

// 平面YUV格式

#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y', 'U', '1', '2')

#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y', 'V', '1', '2')

#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P')

```

3.1.3 压缩格式

```c

#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M', 'J', 'P', 'G')

#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J', 'P', 'E', 'G')

#define V4L2_PIX_FMT_H264 v4l2_fourcc('H', '2', '6', '4')

#define V4L2_PIX_FMT_H265 v4l2_fourcc('H', '2', '6', '5')

```

3.2 视频格式结构

3.2.1 struct v4l2_pix_format

```c

struct v4l2_pix_format {

__u32 width; // 图像宽度

__u32 height; // 图像高度

__u32 pixelformat; // 像素格式

__u32 field; // 场序

__u32 bytesperline; // 每行字节数

__u32 sizeimage; // 图像总大小

__u32 colorspace; // 色彩空间

__u32 priv; // 私有数据

__u32 flags; // 标志

union {

__u32 ycbcr_enc;

__u32 hsv_enc;

};

__u32 quantization; // 量化方式

__u32 xfer_func; // 转换函数

};

```

3.2.2 struct v4l2_pix_format_mplane

```c

struct v4l2_pix_format_mplane {

__u32 width;

__u32 height;

__u32 pixelformat;

__u32 field;

__u32 colorspace;

struct v4l2_plane_pix_format plane_fmt[VIDEO_MAX_PLANES];

__u8 num_planes; // 平面数

__u8 flags;

union {

__u8 ycbcr_enc;

__u8 hsv_enc;

};

__u8 quantization;

__u8 xfer_func;

__u32 reserved[7];

};

```

第4章 视频缓冲区管理

4.1 缓冲区类型

4.1.1 内存映射 (MMAP)

```c

#define V4L2_MEMORY_MMAP 1

```

  • 内核分配缓冲区

  • 用户空间通过mmap映射

4.1.2 用户指针 (USERPTR)

```c

#define V4L2_MEMORY_USERPTR 2

```

  • 用户空间分配缓冲区

  • 驱动直接访问用户空间内存

4.1.3 DMA缓冲区 (DMABUF)

```c

#define V4L2_MEMORY_DMABUF 4

```

  • 使用DMA缓冲区框架

  • 支持零拷贝

4.2 缓冲区状态机

4.2.1 缓冲区状态

```c

enum vb2_buffer_state {

VB2_BUF_STATE_DEQUEUED = 0, // 已出队

VB2_BUF_STATE_PREPARING, // 准备中

VB2_BUF_STATE_QUEUED, // 已入队

VB2_BUF_STATE_ACTIVE, // 活跃状态

VB2_BUF_STATE_DONE, // 处理完成

VB2_BUF_STATE_ERROR, // 错误状态

VB2_BUF_STATE_REQUEUEING, // 重新入队

};

```

4.2.2 缓冲区流转

```

DEQUEUED → PREPARING → QUEUED → ACTIVE → DONE → DEQUEUED

↑ ↓

└─────────────────────────────────────┘

```

4.3 videobuf2框架

4.3.1 核心数据结构

```c

struct vb2_queue {

enum v4l2_buf_type type; // 缓冲区类型

unsigned int io_modes; // IO模式

const struct vb2_mem_ops *mem_ops; // 内存操作

const struct vb2_ops *ops; // 驱动操作

void *drv_priv; // 驱动私有数据

unsigned int buf_struct_size; // 缓冲区结构大小

struct mutex *lock; // 锁

struct list_head queued_list; // 已入队列表

atomic_t owned_by_drv_count; // 驱动持有计数

void *alloc_ctx; // 分配上下文

unsigned int min_buffers_needed; // 最小缓冲区数

};

```

4.3.2 内存操作回调

```c

struct vb2_mem_ops {

void *(*alloc)(struct vb2_buffer *vb, unsigned long size);

void (*put)(void *buf_priv);

struct dma_buf *(*get_dmabuf)(void *buf_priv, unsigned long flags);

void *(*get_userptr)(struct vb2_buffer *vb, unsigned long vaddr,

unsigned long size, enum dma_data_direction dma_dir);

void (*put_userptr)(void *buf_priv);

void (*prepare)(void *buf_priv);

void (*finish)(void *buf_priv);

void (*attach_dmabuf)(struct vb2_buffer *vb, struct dma_buf *dbuf);

void (*detach_dmabuf)(struct vb2_buffer *vb);

int (*map_dmabuf)(void *buf_priv);

void (*unmap_dmabuf)(void *buf_priv);

void *(*vaddr)(void *buf_priv);

void *(*cookie)(void *buf_priv);

unsigned int (*num_users)(void *buf_priv);

int (*mmap)(void *buf_priv, struct vm_area_struct *vma);

};

```

第5章 V4L2控制框架

5.1 控制类型

5.1.1 标准控制

```c

// 基础控制

#define V4L2_CID_BRIGHTNESS 0x00980900

#define V4L2_CID_CONTRAST 0x00980901

#define V4L2_CID_SATURATION 0x00980902

#define V4L2_CID_HUE 0x00980903

// 白平衡

#define V4L2_CID_AUTO_WHITE_BALANCE 0x0098090c

#define V4L2_CID_WHITE_BALANCE_TEMPERATURE 0x0098090f

// 曝光控制

#define V4L2_CID_EXPOSURE_AUTO 0x00980912

#define V4L2_CID_EXPOSURE_ABSOLUTE 0x00980913

```

5.1.2 自定义控制

```c

#define V4L2_CID_PRIVATE_BASE 0x08000000

```

5.2 控制结构

5.2.1 struct v4l2_ctrl

```c

struct v4l2_ctrl {

struct list_head node;

struct v4l2_ctrl_handler *handler;

struct v4l2_ctrl **cluster;

unsigned int ncontrols;

unsigned int done:1;

unsigned int id; // 控制ID

const char *name; // 控制名称

enum v4l2_ctrl_type type; // 控制类型

s32 minimum, maximum, default_value;

u32 step;

u32 menu_skip_mask;

const char * const *qmenu;

const s64 *qmenu_int;

unsigned long flags;

s32 val; // 当前值

struct v4l2_ctrl_ops *ops;

};

```

5.2.2 控制类型枚举

```c

enum v4l2_ctrl_type {

V4L2_CTRL_TYPE_INTEGER = 1,

V4L2_CTRL_TYPE_BOOLEAN = 2,

V4L2_CTRL_TYPE_MENU = 3,

V4L2_CTRL_TYPE_BUTTON = 4,

V4L2_CTRL_TYPE_INTEGER64 = 5,

V4L2_CTRL_TYPE_CTRL_CLASS = 6,

V4L2_CTRL_TYPE_STRING = 7,

V4L2_CTRL_TYPE_BITMASK = 8,

V4L2_CTRL_TYPE_INTEGER_MENU = 9,

V4L2_CTRL_TYPE_U8 = 0x0100,

V4L2_CTRL_TYPE_U16 = 0x0101,

V4L2_CTRL_TYPE_U32 = 0x0102,

};

```

第6章 子设备框架

6.1 子设备操作

6.1.1 子设备操作结构

```c

struct v4l2_subdev_ops {

const struct v4l2_subdev_core_ops *core;

const struct v4l2_subdev_tuner_ops *tuner;

const struct v4l2_subdev_audio_ops *audio;

const struct v4l2_subdev_video_ops *video;

const struct v4l2_subdev_vbi_ops *vbi;

const struct v4l2_subdev_ir_ops *ir;

const struct v4l2_subdev_sensor_ops *sensor;

const struct v4l2_subdev_pad_ops *pad;

};

```

6.1.2 核心操作

```c

struct v4l2_subdev_core_ops {

int (*log_status)(struct v4l2_subdev *sd);

int (*s_io_pin_config)(struct v4l2_subdev *sd, size_t n,

struct v4l2_subdev_io_pin_config *pincfg);

int (*init)(struct v4l2_subdev *sd, u32 val);

int (*load_fw)(struct v4l2_subdev *sd);

int (*reset)(struct v4l2_subdev *sd, u32 val);

int (*s_gpio)(struct v4l2_subdev *sd, u32 val);

int (*s_power)(struct v4l2_subdev *sd, int on);

int (*interrupt_service_routine)(struct v4l2_subdev *sd,

u32 status, bool *handled);

int (*subscribe_event)(struct v4l2_subdev *sd,

struct v4l2_fh *fh,

struct v4l2_event_subscription *sub);

int (*unsubscribe_event)(struct v4l2_subdev *sd,

struct v4l2_fh *fh,

struct v4l2_event_subscription *sub);

};

```

6.2 子设备注册与使用

6.2.1 注册函数

```c

int v4l2_subdev_init(struct v4l2_subdev *sd,

const struct v4l2_subdev_ops *ops);

int v4l2_async_register_subdev(struct v4l2_subdev *sd);

void v4l2_async_unregister_subdev(struct v4l2_subdev *sd);

```

6.2.2 子设备调用

```c

// 调用子设备操作

v4l2_subdev_call(sd, video, s_stream, 1);

v4l2_subdev_call(sd, core, s_power, 1);

```

第7章 媒体控制器框架

7.1 媒体控制器概念

7.1.1 核心概念

  • **媒体设备** (Media Device): 顶级媒体设备

  • **实体** (Entity): 硬件组件(传感器、ISP等)

  • **接口** (Pad): 实体的输入/输出接口

  • **链接** (Link): 实体间的连接关系

7.1.2 数据结构

```c

struct media_device {

struct device *dev;

char model[32];

char driver_name[32];

struct media_entity_graph graph;

struct list_head entities;

struct mutex graph_mutex;

};

struct media_entity {

struct list_head list;

struct media_device *graph_obj.mdev;

u32 id;

const char *name;

u32 type;

u32 revision;

u32 flags;

u32 group_id;

u16 num_pads;

u16 num_links;

u16 num_backlinks;

struct media_pad *pads;

struct media_link *links;

};

```

7.2 媒体拓扑配置

7.2.1 创建链接

```c

struct media_link *media_create_pad_link(struct media_entity *source,

u16 source_pad,

struct media_entity *sink,

u16 sink_pad,

u32 flags);

```

7.2.2 设备树配置

```dts

ports {

#address-cells = <1>;

#size-cells = <0>;

port@0 {

reg = <0>;

/* 连接到ISP输入 */

isp_in: endpoint {

remote-endpoint = <&sensor_out>;

bus-width = <8>;

hsync-active = <1>;

vsync-active = <1>;

};

};

};

```

第8章 流控制与同步

8.1 流控制机制

8.1.1 启动/停止流

```c

int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type);

int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type);

```

8.1.2 缓冲区处理

```c

int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);

int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking);

```

8.2 同步机制

8.2.1 时间戳

```c

struct timeval timestamp; // V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC

```

8.2.2 事件通知

```c

struct v4l2_event {

u32 type;

union {

struct v4l2_event_vsync vsync;

struct v4l2_event_ctrl ctrl;

u8 data[64];

} u;

u32 pending;

u32 sequence;

struct timespec timestamp;

u32 id;

u32 reserved[8];

};

```

第9章 驱动开发最佳实践

9.1 错误处理

9.1.1 资源管理

```c

static int my_driver_probe(struct platform_device *pdev)

{

struct my_device *dev;

int ret;

dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);

if (!dev)

return -ENOMEM;

// 使用devm_系列函数管理资源

dev->clk = devm_clk_get(&pdev->dev, "aclk");

if (IS_ERR(dev->clk)) {

ret = PTR_ERR(dev->clk);

dev_err(&pdev->dev, "Failed to get clock: %d\n", ret);

return ret;

}

// 注册设备

ret = video_register_device(&dev->vdev, VFL_TYPE_VIDEO, -1);

if (ret) {

dev_err(&pdev->dev, "Failed to register video device\n");

return ret;

}

return 0;

}

```

9.2 性能优化

9.2.1 零拷贝支持

```c

// 支持DMABUF

.queue->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;

// 实现DMABUF操作

static struct vb2_mem_ops my_memops = {

.get_dmabuf = my_get_dmabuf,

.attach_dmabuf = my_attach_dmabuf,

.map_dmabuf = my_map_dmabuf,

.unmap_dmabuf = my_unmap_dmabuf,

};

```

9.2.2 中断处理优化

```c

static irqreturn_t my_irq_handler(int irq, void *dev_id)

{

struct my_device *dev = dev_id;

struct my_buffer *buf;

spin_lock(&dev->lock);

if (list_empty(&dev->active_list)) {

spin_unlock(&dev->lock);

return IRQ_NONE;

}

buf = list_first_entry(&dev->active_list, struct my_buffer, list);

list_del(&buf->list);

spin_unlock(&dev->lock);

// 标记缓冲区完成

buf->vb.vb2_buf.timestamp = ktime_get_ns();

vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);

return IRQ_HANDLED;

}

```

第10章 调试与测试

10.1 调试工具

10.1.1 内核调试

```bash

启用调试输出

echo 8 > /proc/sys/kernel/printk

查看驱动消息

dmesg | grep -i v4l2

调试级别控制

#define debug 1

#ifdef debug

#define v4l2_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args)

#else

#define v4l2_dbg(fmt, args...)

#endif

```

10.1.2 用户空间工具

```bash

列出设备

v4l2-ctl --list-devices

查看设备能力

v4l2-ctl -d /dev/video0 --info

查看格式

v4l2-ctl -d /dev/video0 --list-formats-ext

测试采集

v4l2-ctl -d /dev/video0 --stream-mmap=3 --stream-count=100 --stream-to=test.raw

```

10.2 单元测试

10.2.1 测试用例

```c

// 模拟硬件中断

static void simulate_frame(struct work_struct *work)

{

struct my_device *dev = container_of(work, struct my_device, frame_work);

struct my_buffer *buf;

if (list_empty(&dev->buf_list))

return;

buf = list_first_entry(&dev->buf_list, struct my_buffer, list);

list_del(&buf->list);

// 填充测试数据

fill_test_pattern(buf->vaddr, dev->pix_fmt.width, dev->pix_fmt.height);

// 通知缓冲区完成

buf->vb.vb2_buf.timestamp = ktime_get_ns();

vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);

}

```

附录A: V4L2 IOCTL命令速查

A.1 设备信息

```c

VIDIOC_QUERYCAP // 查询设备能力

VIDIOC_ENUM_FMT // 枚举格式

VIDIOC_G_FMT // 获取格式

VIDIOC_S_FMT // 设置格式

VIDIOC_TRY_FMT // 尝试格式

```

A.2 缓冲区管理

```c

VIDIOC_REQBUFS // 请求缓冲区

VIDIOC_QUERYBUF // 查询缓冲区

VIDIOC_QBUF // 入队缓冲区

VIDIOC_DQBUF // 出队缓冲区

VIDIOC_CREATE_BUFS // 创建缓冲区

VIDIOC_PREPARE_BUF // 准备缓冲区

VIDIOC_EXPBUF // 导出缓冲区

```

A.3 流控制

```c

VIDIOC_STREAMON // 启动流

VIDIOC_STREAMOFF // 停止流

```

A.4 控制接口

```c

VIDIOC_QUERYCTRL // 查询控制

VIDIOC_QUERYMENU // 查询菜单

VIDIOC_G_CTRL // 获取控制值

VIDIOC_S_CTRL // 设置控制值

VIDIOC_G_EXT_CTRLS // 获取扩展控制

VIDIOC_S_EXT_CTRLS // 设置扩展控制

VIDIOC_TRY_EXT_CTRLS // 尝试扩展控制

```

A.5 输入输出

```c

VIDIOC_ENUMINPUT // 枚举输入

VIDIOC_G_INPUT // 获取当前输入

VIDIOC_S_INPUT // 选择输入

VIDIOC_ENUMOUTPUT // 枚举输出

VIDIOC_G_OUTPUT // 获取当前输出

VIDIOC_S_OUTPUT // 选择输出

```

A.6 其他

```c

VIDIOC_G_PARM // 获取参数

VIDIOC_S_PARM // 设置参数

VIDIOC_G_STD // 获取标准

VIDIOC_S_STD // 设置标准

VIDIOC_ENUMSTD // 枚举标准

VIDIOC_ENUM_FRAMESIZES // 枚举帧大小

VIDIOC_ENUM_FRAMEINTERVALS // 枚举帧间隔

```

附录B: 常见问题解决

B.1 格式协商失败

**问题**: 应用程序请求的格式驱动不支持

**解决**:

  1. 在驱动中正确实现枚举格式

  2. 在try_fmt中验证格式参数

  3. 支持标准格式转换

B.2 DMA内存分配失败

**问题**: CMA内存不足或对齐错误

**解决**:

  1. 检查内核CMA配置

  2. 确保缓冲区大小正确对齐

  3. 考虑使用DMABUF导入

B.3 流控制问题

**问题**: 启动/停止流失败

**解决**:

  1. 确保在streamon之前有足够缓冲区

  2. 正确处理硬件启动顺序

  3. 实现正确的错误恢复机制

这个V4L2驱动开发指南涵盖了从基础概念到高级特性的完整知识体系。理解这些概念后,你将能够:

  1. 设计并实现V4L2驱动

  2. 调试和优化驱动性能

  3. 集成复杂的多媒体硬件

  4. 提供稳定的用户空间API

建议在实际开发中结合内核源码和现有驱动进行学习,逐步掌握V4L2驱动的开发技巧。

相关推荐
漫随流水2 小时前
leetcode回溯算法(77.组合)
数据结构·算法·leetcode·回溯算法
超级大福宝3 小时前
【力扣200. 岛屿数量】的一种错误解法(BFS)
数据结构·c++·算法·leetcode·广度优先
一分之二~7 小时前
回溯算法--解数独
开发语言·数据结构·c++·算法·leetcode
不如语冰7 小时前
AI大模型入门1.1-python基础-数据结构
数据结构·人工智能·pytorch·python·cnn
未来之窗软件服务7 小时前
计算机等级考试—哈希线性探测解答—东方仙盟
数据结构·哈希算法·散列表·计算机软考·仙盟创梦ide·东方仙盟
苦藤新鸡8 小时前
18.矩阵同行同列全置零
数据结构·c++·算法·力扣
wm10438 小时前
代码随想录 第六天
数据结构·算法
皮蛋sol周8 小时前
嵌入式学习数据结构(三)栈 链式 循环队列
arm开发·数据结构·学习·算法··循环队列·链式队列
Pluchon9 小时前
硅基计划4.0 算法 动态规划入门
java·数据结构·算法·动态规划