嵌入式流媒体消息分发队列设计

在流媒体系统设计中,经常会涉及多线程间的通信问题,需要相互分发消费一些信息以及实时音视频数据,如何才能高效安全的简洁的实现这一目标呢, 可以采用ringbuffer,也可以采用链表等算法。我在实践中做了一个基于信号量和固定指针数组的方案,实现了简单的数据发布订阅,pMessage可以自定义为一个适配自己的消息传递数据结构指针,用于传递消息,如数据指向的指针,数据类型,时间戳,数据长度,或者信令,在嵌入式系统中,采用预分配的全局数组,可以减少动态分配带来的风险和时间波动。通过设置一些信号量及互斥来实现系统级的线程调度,为了使使用更简洁,封装了一些简单的api,实现音频信息 视频信息以及信令信息的接口,将具体的逻辑封装起来,线程中直接调用这些接口就可以实现系统级的订阅等待和数据发布功能,当然这个代码不一定设计最科学和合理,但的确为我的系统带来了多线程处理过程的简洁明快的好处,也在实践中运行良好,现将他开源出来,也希望各位大佬指正,帮助我提高。好了,各位有啥好的意见和建议欢迎跟我交流。本代码用于我的嵌入式webrtc系统,大大简化了我的系统的复杂度。

cpp 复制代码
#include <stdio.h> 
#include <pthread.h> 
#include<semaphore.h>
#include "common.h"
#define BUFFER_SIZE 50 // 缓冲区数量 
struct prodcons 
{ 
	// 缓冲区相关数据结构 
	pMessage buffer[BUFFER_SIZE]; /* 实际数据存放的数组*/ 
	pthread_mutex_t lock; /* 互斥体lock ⽤于对缓冲区的互斥操作 */ 
	int readpos, writepos; /* 读写指针*/ 
	pthread_cond_t notempty; /* 缓冲区⾮空的条件变量 */ 
	pthread_cond_t notfull; /* 缓冲区未满的条件变量 */ 
}; 
#define OVER ( - 1) 
struct prodcons pmsgbuffer; 
struct prodcons pvideo_streambuffer; 
struct prodcons paudio_streambuffer; 
struct prodcons pplayvideo_streambuffer; 
struct prodcons pplayaudio_streambuffer; 

sem_t sem_answerwait, sem_offerwait,sem_videostreamwait,sem_audiostreamwait,sem_playvideostreamwait,sem_playaudiostreamwait;
/* 初始化缓冲区结构 */ 
void init(struct prodcons *b) 
{ 
	pthread_mutex_init(&b->lock, NULL); 
	pthread_cond_init(&b->notempty, NULL); 
	pthread_cond_init(&b->notfull, NULL); 
	b->readpos = 0; 
	b->writepos = 0; 
} 
/* 将产品放⼊缓冲区,这⾥是存⼊⼀个整数*/ 
void put(struct prodcons *b, pMessage data) 
{ 
	pthread_mutex_lock(&b->lock); 
	/* 等待缓冲区未满*/ 
	if ((b->writepos + 1) % BUFFER_SIZE == b->readpos) 
	{ 
	  pthread_cond_wait(&b->notfull, &b->lock); 
	} 
	/* 写数据,并移动指针 */ 
	b->buffer[b->writepos] = data; 
	b->writepos++; 
	if (b->writepos >= BUFFER_SIZE) 
	  b->writepos = 0; 
	/* 设置缓冲区⾮空的条件变量*/ 
	pthread_cond_signal(&b->notempty); 
	pthread_mutex_unlock(&b->lock); 
}  
/* 从缓冲区中取出整数*/ 
pMessage get(struct prodcons *b) { 
	pMessage data; 
	pthread_mutex_lock(&b->lock); 
	/* 等待缓冲区⾮空*/ 
	if (b->writepos == b->readpos) 
	{ 
	  pthread_cond_wait(&b->notempty, &b->lock); 
	} 
	/* 读数据,移动读指针*/ 
	data = b->buffer[b->readpos]; 
	b->readpos++; 
	if (b->readpos >= BUFFER_SIZE) 
	   b->readpos = 0; 
	/* 设置缓冲区未满的条件变量*/
	pthread_cond_signal(&b->notfull); 
	pthread_mutex_unlock(&b->lock); 
	return data; 
} 
/* 将产品放⼊缓冲区,这⾥是存⼊⼀个整数*/ 
void putstream(struct prodcons *b, ptstreamInfo data) 
{ 
	pthread_mutex_lock(&b->lock); 
	/* 等待缓冲区未满*/ 
	if ((b->writepos + 1) % BUFFER_SIZE == b->readpos) 
	{ 
	  pthread_cond_wait(&b->notfull, &b->lock); 
	} 
	/* 写数据,并移动指针 */ 
	b->buffer[b->writepos] = data; 
	b->writepos++; 
	if (b->writepos >= BUFFER_SIZE) 
	  b->writepos = 0; 
	/* 设置缓冲区⾮空的条件变量*/ 
	pthread_cond_signal(&b->notempty); 
	pthread_mutex_unlock(&b->lock); 
}  
/* 从缓冲区中取出整数*/ 
ptstreamInfo getstream(struct prodcons *b) { 
	ptstreamInfo data; 
	pthread_mutex_lock(&b->lock); 
	/* 等待缓冲区⾮空*/ 
	if (b->writepos == b->readpos) 
	{ 
	  pthread_cond_wait(&b->notempty, &b->lock); 
	} 
	/* 读数据,移动读指针*/ 
	data = b->buffer[b->readpos]; 
	b->readpos++; 
	if (b->readpos >= BUFFER_SIZE) 
	   b->readpos = 0; 
	/* 设置缓冲区未满的条件变量*/
	pthread_cond_signal(&b->notfull); 
	pthread_mutex_unlock(&b->lock); 
	return data; 
} 
void initmsgqueue(void) {
	sem_init(&sem_offerwait,0,0);
	sem_init(&sem_answerwait,0,0);
    sem_init(&sem_videostreamwait,0,0);
	sem_init(&sem_audiostreamwait,0,0);
	sem_init(&sem_playvideostreamwait,0,0);
	sem_init(&sem_playaudiostreamwait,0,0);
	init(&pmsgbuffer);//信令消息
	init(&pvideo_streambuffer);//视频流
	init(&paudio_streambuffer);//音频流
	init(&pplayvideo_streambuffer);//视频流
	init(&pplayaudio_streambuffer);//音频流
}
void closemsgqueue(void) {
    sem_destroy(&sem_answerwait);
    sem_destroy(&sem_offerwait);
	sem_destroy(&sem_videostreamwait);
	sem_destroy(&sem_audiostreamwait);
	sem_destroy(&sem_playvideostreamwait);
	sem_destroy(&sem_playaudiostreamwait);	
}
int sendkvsmsg(pMessage pmsg){
	put(&pmsgbuffer,pmsg);
	sem_post(&sem_offerwait);
	printf("sendkvsmsg %s\r\n",pmsg->Mode);
	return 0;
}
int receivekvsmsg(pMessage  *ppmsg){
	sem_wait(&sem_offerwait);
	*ppmsg = get(&pmsgbuffer);
	printf("receivekvsmsg %s\r\n",(*ppmsg)->Mode);
	return 0;
}

int sendkvsstream(ptstreamInfo pstream){
	switch(pstream->streamtype){
		case STREAM_VIDEO:
		    // sem_wait(&sem_videostreamwait);
			putstream(&pvideo_streambuffer,pstream);
			sem_post(&sem_videostreamwait);
			// printf("sendkvsstream %d-> %d\r\n",pstream->streamtype,pstream->size);
		break;
        case STREAM_AUDIO:
			putstream(&paudio_streambuffer,pstream);
			sem_post(&sem_audiostreamwait);
			// printf("sendkvsstream %d-> %d\r\n",pstream->streamtype,pstream->size);
		break;
		default:
		break;
		}       
	return 0;
}
int receivekvsvideostream(ptstreamInfo  *pstream){
	sem_wait(&sem_videostreamwait);
	*pstream = getstream(&pvideo_streambuffer);
	// sem_post(&sem_videostreamwait);
	// printf("receivekvsvideostream %d->%d\r\n",(*pstream)->streamtype,(*pstream)->size);
	return 0;
}
int receivekvsaudiostream(ptstreamInfo  *pstream){
	sem_wait(&sem_audiostreamwait);
	*pstream = getstream(&paudio_streambuffer);
	// printf("receivekvsaudiostream %d->%d\r\n",(*pstream)->streamtype,(*pstream)->size);
	return 0;
}
//play
int sendkvsplaystream(ptstreamInfo pstream){
	switch(pstream->streamtype){
		case STREAM_VIDEO:
		    // sem_wait(&sem_videostreamwait);
			putstream(&pplayvideo_streambuffer,pstream);
			sem_post(&sem_playvideostreamwait);
			// printf("sendkvsstream %d-> %d\r\n",pstream->streamtype,pstream->size);
		break;
        case STREAM_AUDIO:
			putstream(&pplayaudio_streambuffer,pstream);
			sem_post(&sem_playaudiostreamwait);
			// printf("sendkvsstream %d-> %d\r\n",pstream->streamtype,pstream->size);
		break;
		default:
		break;
		}       
	return 0;
}
int receivekvspalyvideostream(ptstreamInfo  *pstream){
	sem_wait(&sem_playvideostreamwait);
	*pstream = getstream(&pplayvideo_streambuffer);
	// sem_post(&sem_videostreamwait);
	// printf("receivekvsvideostream %d->%d\r\n",(*pstream)->streamtype,(*pstream)->size);
	return 0;
}
int receivekvsplayaudiostream(ptstreamInfo  *pstream){
	sem_wait(&sem_playaudiostreamwait);
	*pstream = getstream(&pplayaudio_streambuffer);
	// printf("receivekvsaudiostream %d->%d\r\n",(*pstream)->streamtype,(*pstream)->size);
	return 0;
}
相关推荐
暮色_年华4 分钟前
Modern Effective C++item 9:优先考虑别名声明而非typedef
c++
重生之我是数学王子12 分钟前
QT基础 编码问题 定时器 事件 绘图事件 keyPressEvent QT5.12.3环境 C++实现
开发语言·c++·qt
WINDHILL_风丘科技22 分钟前
Softing工业将OPC UA信息建模集成到边缘应用和安全集成服务器中
物联网·网关·工业边缘·opc·工业自动化
我们的五年36 分钟前
【Linux课程学习】:进程程序替换,execl,execv,execlp,execvp,execve,execle,execvpe函数
linux·c++·学习
做人不要太理性1 小时前
【C++】深入哈希表核心:从改造到封装,解锁 unordered_set 与 unordered_map 的终极奥义!
c++·哈希算法·散列表·unordered_map·unordered_set
程序员-King.1 小时前
2、桥接模式
c++·桥接模式
chnming19871 小时前
STL关联式容器之map
开发语言·c++
程序伍六七1 小时前
day16
开发语言·c++
小陈phd2 小时前
Vscode LinuxC++环境配置
linux·c++·vscode
火山口车神丶2 小时前
某车企ASW面试笔试题
c++·matlab