Gstreamer学习与systemV 共享内存实例

前言

最近在做Gstreamer视频传输过程中,因涉及到多进程间的通信,本来使用本地socket方式进行传输,发现每秒的帧率会被降低,因此决定用共享内存试一下,看看是否能够快一点。经过多番文档阅读,发现存在syetemV与POSIX两种方式的共享内存,并且区别还是蛮明显的,因此决定两者都试一下。
由于systemV共享内存之间并没有进程同步,因此还需要信号量进行进程间同步操作,systemV的信号量比之POSIX信号量又有很大不同,因此采用SystemV信号量为SystemV共享内存做进程同步操作。实际需求如下:

需求说明

  • 进程A:Gstreamer进程,使用appsrc、vpuenc_h264、appsink三个元件对视频进行H264编码,appsrc通过元件的信号获取NV12格式的图像数据,vpuenc_h264元件进行编码,appsink获取编码后的H264帧、appsink的信号回调函数负责通过共享内存与信号量,将数据传输到进程B
  • 进程B:视频推动进程,通过共享内存获取H264视频帧,使用rtmp方式推送到服务端

进程A

进程A还有一个ipu_thread线程,负责将RGB32格式的数据转换为NV12格式,其与appsrc之间通过POSIX信号量进行同步。
进程A还通过SystemV信号量实现了一个二值信号量封装,用来进行进程间同步

  • int InitSemAvilable(int semId, int semNum)
  • int InitSemInUse(int semId, int semNum)
  • int WaitSem(int semId, int semNum)
  • int PostSem(int semId, int semNum)
  • int DeleteSem(int semId, int semNum)
#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <gst/app/gstappsink.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/un.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>
#include <ipu.h>

typedef struct _GstDataStruct{
   
	GstElement *pipeline;
	GstElement *app_source;
	GstElement *video_convert;
	GstElement *h264_encoder;
	GstElement *app_sink;
	guint sourceid;        	// To control the GSource
	guint app_src_index;
	guint app_sink_index;
	guint bus_watch_id;
	GstBus *bus;
	GMainLoop *loop;  		// GLib's Main Loop
	int frame_rate;
	int gop_size;
	int bit_rate;
	int quant;
} GstDataStruct;

typedef struct
{
   
	struct fb_var_screeninfo vinfo;	// 可变的STOP显示屏幕信息
	struct fb_fix_screeninfo finfo;
	int width;					// width 宽度
	int height;					// height 高度
	int bpp;					// bit per pixel 像素的位数
	int rowsize;				// 屏幕一行所占字节数
	int real_len;				// 实际显示区域的字节数
	int total_len;				// 显示区域总字节数,即长度
	int offset;					// 实际显示位置在总长度中的偏移量
}FbInfoStruct;


#define VIDEO_BUF_SIZE	((128 * 1024 * 1024) - sizeof(unsigned int)*3)
typedef struct
{
   
	unsigned int head;
	unsigned int len;
	unsigned int index;
	unsigned char data[VIDEO_BUF_SIZE];
}ShmVideo360Struct;

union semun
{
   
	int val;
	struct semid_ds *buf;
	unsigned short int *array;
	struct seminfo *__buf;
};

static int fb_init(void);
static int gst_pipeline_init(void);
static void new_h264_sample_on_appsink (GstElement *sink, GstDataStruct *pGstData);
static void start_feed (GstElement * pipeline, guint size, GstDataStruct *pGstData);
static void stop_feed (GstElement * pipeline, GstDataStruct *pGstData);
static gboolean bus_msg_call(GstBus *bus, GstMessage *msg, GstDataStruct *pGstData);
static void *ipu_thread(void *arg);

struct IPU_PHY_MEM {
   
	char *vaddr;
	unsigned int paddr;
	unsigned int size;
};

struct ipu_task gtask;
struct IPU_PHY_MEM ipu_pmem;
static GstDataStruct GstData;
static FbInfoStruct FbInfo;

int fd_fb;
int fd_ipu;
sem_t sem_frame_put;
sem_t sem_frame_get;

#define UNIX_DOMAIN "/home/root/UNIX.domain"
#define SHM_KEY		(0x8765)
#define SEM_KEY		(0x4321)
#define OBJ_PERMS	(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
int shmid;									//共享内存标识符
void *shm = NULL;							//分配的共享内存的原始首地址
ShmVideo360Struct *shared360 = NULL;		//指向shm

int semid;
#define USER_SEM_UNDO (FALSE)		//进程终止时,是否撤销对sem的操作
#define RETRY_ON_EINTR (FALSE)		//semop操作被信号中断时是否重试
#define WRITE_SEM		(0)
#define READ_SEM		(1)

int InitSemAvilable(int semId, int semNum)
{
   
	union semun arg;
	arg.val = 1;
	return semctl(semId, semNum, SETVAL, arg);
}

int InitSemInUse(int semId, int semNum)
{
   
	union semun arg;
	arg.val = 0;
	return semctl(semId, semNum, SETVAL, arg);
}

int WaitSem(int semId, int semNum)
{
   
	struct sembuf sops;

	sops.sem_num = semNum;
	sops.sem_op = -1;
	sops.sem_flg = USER_SEM_UNDO ? SEM_UNDO : 0;
	while(semop(semId, &sops, 1) == -1)
	{
   
		if(errno != EINTR || !RETRY_ON_EINTR)
			return -1;
	}
	return 0;
}

int PostSem(int semId, int semNum)
{
   
	struct sembuf sops;

	sops.sem_num = semNum;
	sops.sem_op = 1;
	sops.sem_flg = USER_SEM_UNDO ? SEM_UNDO : 0;
	return semop(semId, &sops, 1);
}
int DeleteSem(int semId, int semNum)
{
   
	union semun arg;
	return semctl(semId, semNum, IPC_RMID, arg);
}

int DeleteShm(int shmid, void* shm)
{
   
	if(shmdt(shm) == -1)									//把共享内存从当前进程中分离
	{
   
		printf("shmdt failed\n");
		return -1;
	}

	if(shmctl(shmid, IPC_RMID, 0) == -1)					//删除共享内存
	{
   
		printf("shmctl(IPC_RMID) failed\n");
		return -1;
	}
	return 0;
}

int main(int argc, char *argv[])
{
   
	int ret = 0;
	pthread_t tid;

	printf("================ imx60 360 main start =============\n");
	memset (&GstData, 0, sizeof (GstDataStruct));
	sem_init(&sem_frame_put, 0, 0);
	sem_init(&sem_frame_get, 0, 0);

	if(argc == 5)
	{
   
		GstData.frame_rate = atoi(argv[1]);
		GstData.gop_size = atoi(argv[2]);
		GstData.bit_rate = atoi(argv[3]);
		GstData.quant = atoi(argv[4]);
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值