视频处理模块优化

上一版的不足

上一版的不足在于其拓展性弱(只支持一路输入源),参数配置麻烦(需要通过宏定义修改)。新版将不再采用宏定义方式进行配置,而是新增一个配置结构体,用户可以在该结构体里面配置信息构建自定义管道,且支持任意数量的输入源同时工作。

0. 配置参数

这一版将配置参数通过enum和union进行统一管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/* SOURCE_TYPE */

typedef enum {
SOURCE_TYPE_V4L2,
SOURCE_TYPE_UDP,
SOURCE_TYPE_TEST,
} SOURCE_TYPE;

/* QUEUE_MODE */

typedef enum {
QUEUE_MODE_FORCE,
QUEUE_MODE_PASS,
} QUEUE_MODE;

/* CODER TYPE */
typedef enum {
CODER_SOFT,
CODER_MPP,
} CODER;

/* error type */

#define EINPUT 1
#define EALLOC 2
#define ELINK 3
#define ESIG 4
#define EPUSH 5
#define EPOP 6

/* video configure */

typedef enum {
VIDEO_FORMAT_RGB,
VIDEO_FORMAT_NV12,
} VIDEO_FORMAT;


typedef union {
int port;
const char *dev;
} SOURCE_ID;

1. GstConfig配置结构体

通过一个配置结构体管理一个视频管道的配置信息,可以在程序中自定义管道。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
typedef struct {
uint8_t USE_RGA;
uint8_t USE_RECORD;
uint8_t USE_SHOW;
int max_queue_length;
guint sourceid;
long frame_count;

int video_width;
int video_height;
int video_fps;
VIDEO_FORMAT video_format;

SOURCE_TYPE source_type;
SOURCE_ID source_id;
QUEUE_MODE queue_mode;
CODER encode_type;
CODER decode_type;

} GstConfig;

2. GstApiData结构体

这个结构体的作用相当于Linux驱动中的cdev, 其中的gst_file_operations相当于cdev的file_operations,其中包含read和write函数需要用户实现或使用系统默认。该结构体的功能包括

  • 负责管理所需Gstreamer组件的初始化以及管道的搭建和运行
  • 用户程序通过该结构体访问视频数据

与上一般的不同在于,GstElement不再根据宏定义配置定义该结构体属性,而是通过GstConfig的配置在初始化函数中构造pipeline中的元素,这些元素直接添加到pipeline和record_pipeline中被其自动管理。此外GstApiData里面多了一个MemoryPool,这样可以实现每一路输入源都有一个内存池来管理内存分配。

1
2
3
4
5
6
7
8
9
typedef struct {
GstConfig* cfg;
gst_file_operations *fops;
GstElement *pipeline, *record_pipeline;
FrameQueue *fqueue, *rqueue;
GstBus *bus, *record_bus;
MemoryPool* mem_pool;
GMainLoop *main_loop; /* GLib's Main Loop */
} GstApiData;

使用流程

这里演示一下如何构建V4L2和TEST两路管道,使用户可以读取两路的图像数据并将图像保存为MP4。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
GstApiData *data[2];
// 定义了一个测试输入源配置信息, 设置为720p120fps,不进行视频存储
GstConfig cfg = {
.USE_RGA=0,
.USE_RECORD=0,
.USE_SHOW=0,
.max_queue_length=16,
.video_width=1280,
.video_height=720,
.video_fps=120,
.video_format=VIDEO_FORMAT_RGB,
.source_type=SOURCE_TYPE_TEST,
.queue_mode=QUEUE_MODE_FORCE,
.encode_type=CODER_SOFT,
.decode_type=CODER_SOFT,
};
// 定义了一个V4L2摄像头输入源配置信息,设置为1080p30fps, 打开视频存储管道
GstConfig cfg2 = {
.USE_RGA=0,
.USE_RECORD=1,
.USE_SHOW=0,
.max_queue_length=16,
.video_width=1920,
.video_height=1080,
.video_fps=30,
.video_format=VIDEO_FORMAT_RGB,
.source_type=SOURCE_TYPE_V4L2,
.source_id={ .dev="/dev/video0" },
.queue_mode=QUEUE_MODE_FORCE,
.encode_type=CODER_SOFT,
.decode_type=CODER_SOFT,
};
// 初始化GstApiData结构体构建视频管道
ret = gst_api_init(&data[0], &cfg, &std_fops);
ret = gst_api_init(&data[1], &cfg2, &std_fops);
// 可以查看每个GstApiData的配置信息
gst_print_informations(data[0]);
gst_print_informations(data[1]);
// 启动两路输入源管道,会堵塞
gst_api_try_play(gdata, 2);

// 通过gread(gdata)和gwrite(gdata, rframe)即可完成图像读取和保存