基于UDP的流媒体实现

编程入门 行业动态 更新时间:2024-10-27 16:33:27

基于UDP的<a href=https://www.elefans.com/category/jswz/34/1770639.html style=流媒体实现"/>

基于UDP的流媒体实现

基于UDP的流媒体实现

  • 项目简介
    • 原理图
    • 头文件的定义
    • 资源解析模块
    • 节目单发送线程模块
    • 频道发送模块
    • 流量控制模块
  • 客户端实现
    • 客户端头文件
    • 服务端头文件

项目简介

我们通过UDP来进行流媒体的传输,主要实现音乐的发送,通过UDP来进行组播,可以对应多个客户端,客户端方面,采用mpg123来进行音月资源的解析。

原理图


服务端采用多线程来实现节目单和节目资源的发送,客户端采用多进程,父进程接收资源,和显示节目单,在选择节目后,将资源发送给子进程,子进程来实现资源的解析。
在server端主要需要解析文件资源模块,节目单发送线程,节目资源发送线程和流量控制模块来控制资源发送的速率,接下来我将分模块讲解一下它的实现。

头文件的定义

先看一下代码吧

#ifndef _PROTO_H_
#define _PROTO_H_#include <stdint.h>#define DEFAULT_MGPPOUP		"239.0.0.2"			//广播地址					
#define DEFAULT_RCVPORT		"9000"				//端口#define CHNNUM				100					//节目最大数#define LISTCHNID			0					//节目单的id#define MINCHNID			1					//最小节目号
#define MAXCHNID			(MINCHNID+CHNNUM-1)	//最大节目号#define MSG_CHANNEL_MAX		(65536-20-8)		//资源最大发送量
#define MAX_DATA			(MSG_CHANNEL_MAX-sizeof(uint8_t))#define MSG_LIST_MAX		(65536-20-8)							
#define MAX_ENTRY			(MSG_LIST_MAX-sizeof(uint8_t))struct msg_channel_st		//频道信息
{uint8_t chnid;			//节目iduint8_t data[1];		//传输的数据
}__attribute__((packed));	//不需要对齐struct msg_listentry_st		//节目单信息
{uint8_t chnid;			//节目iduint16_t len;			//长度char desc[1];			//节目单内容
}__attribute__((packed));	struct msg_list_st			//节目单
{uint8_t chnid;			struct msg_listentry_st entry[1];}__attribute__((packed));	#endif // !_PROTO_H_

在这里我们定义了发送节目单的结构体,发送频道信息的结构体,来实现资源发送的实现,同时也方便文件的解析,我们主要通过变参的形式保存资源,因为我们不知道资源文件的大小。在这里我们也设置里一些必要条件的宏,因为这个头文件,会被所以的模块所包含,所以在这里定义一些,必要的参数,比如,组播的地址和端口和结构体的参数。

资源解析模块

我们来先看一下代码

/*medialib.h*/typedef void* mytbf_t;struct mlib_listentry_st
{uint8_t chnid;			char* desc;};int mlib_getchnlist(struct mlib_listentry_st**,int*);	//获取节目资源int mlib_freechnlist(struct mlib_listentry_st*);		//释放文件资源int mlib_readchn(uint8_t, void*, size_t);				//读取指定的节目资源

这是解析资源文件的头文件,主要就是访问资源文件夹,将节目资源的简介和节目号读取,通过在主线程传入mli_listentry_st的指针,在获取文件资源的函数中,来实现传入参数的赋值,所以获取文件资源的函数中,我们传入里结构体指针的指针,同时,我们也要获取到资源的数量,通过要发送资源的数量,我们来指定资源线程的数量。

节目单发送线程模块

先上代码

/*thr_list.h*/
#pragma once
#include "medialib.h"//创建发送线程
int thr_list_create(struct mlib_listentry_st*,int);	//线程的销毁
int thr_list_destroy(void);						  

节目单发送线程就比较简单了,主要在主线程,我们将解析出来的文件结构体传入,之后我们创建线程,来实现节目单的定时发送,就可以了将节目单资源发送过去了。

频道发送模块

频道发送模块和节目单发送线程在定义的头文件上是差不多的,但是在这里我们增加了线程的指定销毁。因为我们要调用资源解析中用到的函数,所以我们才包含了mediali.h的头文件。

#pragma once
#include "medialib.h"int thr_channel_create(struct mlib_listentry_st*);		int thr_channel_destroy(struct mlib_listentry_st*);int thr_channel_destroyall(void);

流量控制模块

/*mytbf.h*/
#pragma once#define MYTBF_MAX 1024
typedef void* mytbf_t;mytbf_t* mytbf_init(int cps, int burst);			//速率和上限int mytbf_fetchtoken(mytbf_t*,int);					//获取令牌int mytbt_returntoken(mytbf_t*,int);				//归还令牌int mytbf_destroy(mytbf_t*);						//销毁

流量控制,就是控制发送的速率,我们可以通过mytbf_init来设置每次发送的速率,通过获取令牌,来获得发送的权限,实现资源发送的速率,因为发送流媒体资源,我们要控制资源的发送的速率,来实现音乐的播放。

客户端实现

客户端头文件

#ifndef _CLIENT_H_
#define _CLIENT_H_#define DEFAULT_PLAYERCMD		"/usr/bin/mpg123 - > /dev/null" struct client_conf_st
{const char* rcvport;const char* mgroup;const char* player_cmd;
};int writen(int fd, const void* vptr, int n);extern struct client_conf_st client_conf;#endif // !_CLIENT_H_

我们来创建一个客户端的结构体,来指定接收端口,组播地址和媒体解析器,同时我们会在客户端fork出子进程,来调用解析器,解析父进程发送过来的资源文件,父进程主要的功能就是,接收节目单资源和频道资源,并且选择指定的频道资源,将资源发送个子进程。

服务端头文件

#pragma once
#define DEFAULT_MEDIADIR	"/var/media"
#define DEFAULT_IF			"ens33"
#include <netinet/ip.h> 
#include <arpa/inet.h>enum
{run_daemon = 1,run_foregrounp};static int daemonize();struct server_conf_st
{const char* rcvport;			//绑定的ipconst char* mgroup;				//广播地址const char* media_dir;			//资源文件const char* runmode;			//运行模式const char* ifname;				//网卡信息
};extern int listenfd;
extern struct sockaddr_in clientaddr;
extern socklen_t clientaddr_len;

在后续我会将我的项目发送到github中,在这里就不在多说了。

更多推荐

基于UDP的流媒体实现

本文发布于:2024-03-10 12:30:11,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1727982.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:流媒体   UDP

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!