linuxc廣播流媒體文件_第1頁
linuxc廣播流媒體文件_第2頁
linuxc廣播流媒體文件_第3頁
linuxc廣播流媒體文件_第4頁
linuxc廣播流媒體文件_第5頁
已閱讀5頁,還剩3頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、linux c 廣播流媒體文件(一) 概要實現(xiàn)的功能,廣播流媒體文件,發(fā)送端和接收端,發(fā)送端分為200個頻道,其中有一個菜單頻道,和其他的數(shù)據頻道,接收端通過客戶端通過菜單選擇數(shù)據頻道,并且通過mpg123播放(二)模塊劃分發(fā)送端菜單發(fā)送模塊: 負責發(fā)送菜單,包括頻道號,以及該頻道相應的描述,以供接收端選擇頻道媒體數(shù)據發(fā)送模塊: 負責發(fā)送各個頻道的媒體數(shù)據媒體資源處理模塊: 負責從媒體目錄中相應文件里面讀取媒體數(shù)據提交給媒體數(shù)據發(fā)送模塊令牌桶: 負責控制發(fā)送數(shù)據的速度,以確保不會因為發(fā)送的速度過快導致接收端緩沖區(qū)滿溢出而丟包發(fā)送和接收時的數(shù)據結構程序的主體(三)實現(xiàn)細節(jié)3.0 發(fā)送和接收時的數(shù)

2、據包結構./src/include/proto.h./src/include/site_types.h#defien CHNNR 200 /* 頻道個數(shù) */#define LISTCHNID 0 /* 節(jié)目單的頻道號 */#define MINCHNID 1 /* 最小頻道號 */#define MAXCHNID (MINCHNID+CHNNR-1) /* 最大頻道號 */#define MSG_CHANNEL_MAX (65536-20-8) /* 一個最大的字節(jié)數(shù) */typedef uint8_t chnid_t; /* 頻道號 */* 數(shù)據頻道發(fā)送的包結構 */struct msg_

3、channel_st chnid_t id; /* MUST BETWEEN MINCHIND, MAXCHIND 頻道號 */ uint8_t data1; /* 流媒體數(shù)據, 當做可邊長類型使用 */ _attribute_(packed); /* 不進行結構體內存對齊,避免網絡通信中,雙方對齊方式不一樣 */#define MSG_LIST_MAX (65536-20-8) struct msg_listentry_st /* 每個頻道的頻道號以及對應的頻道描述 */ chnid_t id; /* MUST BETWEEN MINCHIND, MAXCHIND 頻道號 */ uint16

4、_t len; /* 保存當前這個包的大小,以便得到下一個包的地址 */ uint8_t desrc1; /* 頻道描述, 當做可變長字節(jié)數(shù)組 */ _attribute_(packed);/* 菜單 */struct msg_list_st /* 菜單頻道的包結構 */ chnid_t id; /* MUST BE LISTCHNID 頻道號 */ struct msg_listentry_st entry1; /* 各個頻道的頻道號以及頻道信息, 當做可變長字節(jié)數(shù)組 */ _attribute_(packed);新遇到的函數(shù)或用法不要任意直接使用常量,如果這個常量有意義,那就定義宏來使用,

5、便于后期的維護和代碼的可讀性在兩臺電腦上通過網絡傳輸數(shù)據的時候,不僅要注意大小端的問題,還要注意兩臺電腦之間的內存對齊問題struct list struct list *next; char data0;在32位下,sizeof(struct list)是4個字節(jié),data里面沒有元素,所以是0個字節(jié),但是data的地址是緊貼著struct list末尾的地址的,所以可以這樣使用struct list *ptr = malloc(sizeof(struct list)+20);這個結構體指針指向的空間多出20個字節(jié)來,可以通過data來得到這塊內存的首地址,這樣就實現(xiàn)了一個類似一個可變長字節(jié)

6、的結構體3.1 令牌桶./src/server/mytbf.h ./src/server/mytbf.c 大體的功能是有一個容器,存有多個令牌,當去讀文件的時候先去令牌桶拿令牌,拿到多少個就讀出多少個字節(jié), 規(guī)定令牌桶的最大容量(burst),每秒鐘能拿多少個令牌(字節(jié))(cps),當前桶內剩余的令牌數(shù)(token);桶內的令牌會自動增長,每秒增長cps個令牌/* 主要的數(shù)據結構 */ struct mytbf_st int cps; /* 每秒多少字節(jié) */ int burst; /* 桶的容量 字節(jié)數(shù)*/ int token; /* 當前桶的大小 字節(jié)數(shù)*/ pthread_mutex_t

7、 mut; /* 對token進行加鎖 */ pthread_cond_t cond; /*如果取得時候,令牌桶里面沒有令牌,就會阻塞在這個條件變量上*/ ;tpyedef void mytbf_t; /令牌桶的處理句柄static struct mytbf_st *tbfTBFMAX; /* 令牌桶指針數(shù)組 */static pthread_mutex_t mut_tbf = PTHREAD_MUTEX_INITIALIZER; 用于鎖這個令牌桶數(shù)組static pthread_t tid_timer;static pthread_once_t init_once = PTHREAD_ONC

8、E_INIT;mytbf_t *mytbf_init(int cps, int burst); /初始化化令牌桶,設置這個令牌桶的cps和burst static void module_load(void); /加載時鐘線程, static void *thr_timer_func(void *sed); /這個線程主要同于令牌桶中令牌的自增 static void *module_unload(void); /銷毀和回收時鐘線程,使用的是atexit調用的,當進程結束時運行 static int get_free_pos(); /從令牌桶數(shù)組中得帶沒有使用的令牌桶下標 返回令牌桶的地址,當

9、做句柄int mytbf_fetchtoken(mytbf_t *,int n); /從桶里面取令牌,如果有就取走,沒有就阻塞在條件變量上等待int mytbf_returntoken(mytbf_t *, int n); /如果取得令牌沒有用完,就把剩余的還回去int mytbf_destroy(mytbf_t *); /銷毀令牌桶令牌桶指針數(shù)組的存在是為了令牌桶自增方便,把所有的令牌桶統(tǒng)計一下,通過一個線程輪詢的方式自增,就避免每個令牌桶都使用單獨的自增線程,節(jié)省資源,便于管理.當然,這顯然是一個需要多個線程同時操作的變量,所以需要加鎖新遇到的函數(shù)或用法 /睡眠一秒 struct time

10、spec t; t.tv_sec = 1; /m t.tv_nsec = 0; /ns /* 第一個參數(shù)是要睡多少秒,第二個參數(shù)是如果睡眠被信號打斷,剩余的時間 ,放到循環(huán)里,知道1s全部執(zhí)行完,當跳出循環(huán)*/ while (nanosleep(&t, &t) != 0) if (errno != EINTR) syslog(LOG_ERR, "nanosleep(): %s", strerror(errno); exit(1); /設置程序進程結束時調用的函數(shù)(返回值void,沒有參數(shù)) int atexit(void (*function)(void);

11、 /在線程函數(shù)中,只執(zhí)行一次這個函數(shù)(返回值void,沒有參數(shù)) pthread_once_t once_control = PTHREAD_ONCE_INIT; int pthread_once(pthread_once_t *once_control, void (*init_routine)(void);3.2 媒體資源處理模塊./src/server/medialib.c ./src/server/medialib.h媒體文件的存儲方式是在./tmp/media文件中,一個單獨的文件,里面有存儲著.MP3流媒體文件和desc.test文件(缺一不可),我們根據滿足要求的子文件的個數(shù)來確

12、定頻道的個數(shù),頻道數(shù)新定位200個 /* 主要的數(shù)據結構 */struct mlib_listentry_st /* 每個頻道的描述的結構體 */ chnid_t id; /頻道id char *desc; /頻道的描述,也就是desc.test中的內容;struct channel_context_st /* 存儲頻道的內容信息*/ chnid_t id; /頻道id char *desc; /頻道描述 glob_t mp3glob; /在頻道子目錄中符合相應規(guī)則("*.mp3")的文件名的集合 int pos; /當前讀取的文件名在mp3glob這個文件名的下標 off

13、_t offset; /讀取當前文件的指針偏移 int fd; /當前文件的文件描述符 mytbf_t *tbf; /讀這個文件的令牌桶句柄;/*API*/static struct channel_context_st channelMAXCHNID+1; /存儲所有的頻道內容信息的數(shù)組/* 通過媒體資源目錄,得到當前的頻道列表信息和頻道個數(shù) */int mlib_getchnlist(struct mlib_listentry_st *, int *); static struct channel_context_st *path2entry(const char *path) /把頻道媒

14、體數(shù)據的子目錄路徑傳進去,返回一個當前頻道內容信息的結構體指針 mytbf_t *mytbf_init(int cps, int burst); /初始化這個頻道的令牌桶/根據頻道號找到相對應的資源文件,讀到buf里,返回讀取到的字節(jié)數(shù)ssize_t mlib_readchn(chnid_t cid, void* buf, ssize_t len); int mytbf_fetchtoken(mytbf_t *,int n); /從桶里面取令牌,確定可以讀取的字節(jié)數(shù) static int open_next(chnid_t id); /如果read返回值是0,說明已經讀完,自動讀取下一個文件

15、int mytbf_returntoken(mytbf_t *, int n); /讀取內容成功,如果又沒用完的令牌,就還回去int mlib_freechnlist(struct mlib_listentry_st *); /釋放channel數(shù)組資源函數(shù)的實現(xiàn)細節(jié)int mlib_getchnlist(struct mlib_listentry_st *result, int *resnum) 通過snprintf(path, PATHSIZE, "%s/*", server_conf.media_dir);這一步拼接出"/var/media/*"帶

16、有通配符字符串,server_conf.media_dir這個就是默認的資源路徑("/var/media")(絕對路徑) 再使用glob(path, 0, NULL, &globres)得到符合這個通配符的所有文件名信息,放到globres里面 再根據globres.gl_pathc符合條件的文件路徑個數(shù)確定一共需要創(chuàng)建的頻道個數(shù),在malloc內存相應的菜單項內存 通過輪詢globres.gl_pathvi,范圍globres.gl_pathc,來遍歷每個頻道的媒體文件, 再通過res = path2entry(globres.gl_pathvi);獲取每個頻道的

17、內容(id,描述,流媒體文件等), 然后把path2entry返回的內容轉化成mlib_listentry_st,都放到一個數(shù)組中 然后把頻道的菜單列表和菜單的大小傳出去.ssize_t mlib_readchn(chnid_t cid, void* buf, ssize_t len); 讀取媒體數(shù)據 tbfsize = mytbf_fetchtoken(channelid.tbf, size);首先從;令牌桶獲取令牌 len = pread(channelid.fd, buf, tbfsize, channelid.offset); 從offset的偏移位置讀取數(shù)據 mytbf_return

18、token(channelid.tbf, tbfsize-len);把剩余的令牌換回去新遇到的函數(shù)或用法#include <glob.h>int glob(const char *pattern, int flags, int (*errfunc) (const char *epath, int eerrno), glob_t *pglob);typedef struct size_t gl_pathc; /*gl_pathv里面有多少個符合規(guī)則的文件名 Count of paths matched so far */ char *gl_pathv; /* 字符串的內容 List

19、of matched pathnames. */ size_t gl_offs; /* Slots to reserve in gl_pathv'. 為GLOB_DOOFS保留的 */ glob_t;/* glob函數(shù)搜索匹配函數(shù)pattern中的參數(shù),如/*是匹配根文件下的所有文件(不包含隱藏文件,要找到隱藏文件需要從新匹配),然后將匹配出的結果存放到pglob,即第4個參數(shù)中,第二個參數(shù)能選擇匹配模式,如是否排序,或者在函數(shù)第二次調用時,是否將匹配內容追加到pglob中等,第三個參數(shù)是饞看錯誤信息,一般置為NULL; 使用glob的遞歸調用可以找到系統(tǒng)任意路徑的所有文件 */#in

20、clude <string.h>char *strdup(const char *s); strdup會先用malloc()配置與參數(shù)s字符串相同的空間大小,然后將參數(shù)s字符串的內容復制到該內存地址,然后把返回.返回的地址最后可以利用free來釋放ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset); 和read差不多,不過是從offset這個偏置的位置開始讀文件,而不是從文件指針位置3.3 菜單發(fā)送模塊./src/server/thr_list.h ./src/server/thr_list.c 把通過媒

21、體資源處理模塊得到的菜單信息通過組播發(fā)送出去,每秒一次/* 創(chuàng)建菜單發(fā)送線程 */int thr_list_create(struct mlib_listentry_st *listp, int nr_ent) 把listp和nr_ent傳入到線程函數(shù)中去,這里是用的全局變量的形式 當前的菜單信息是struct mlib_listentry_st這個結構體的,要把它轉化成菜單發(fā)送的數(shù)據包struct msg_list_st 首先根據listp確定struct msg_list_st菜單發(fā)送數(shù)據包的大小.然后malloc內存 然后把菜單項拷過去 死循環(huán)發(fā)送菜單包 間隔1s3.4 菜單發(fā)送模塊給每

22、個頻道創(chuàng)建一個子線程發(fā)送各自頻道的數(shù)據int thr_channel_create(struct mlib_listentry_st *ptr) 創(chuàng)建一個線程函數(shù) static void *thr_channel_func(void *ptr) 通過len = mlib_readchn(ent->id, sbufp->data, datasize);來讀取流媒體內容,發(fā)送出去新遇到的函數(shù)或用法#include <sched.h> int sched_yield(void);當線程調用這個函數(shù)時,會讓主動出CPU使用權,讓其他線程得到執(zhí)行(四) 程序的主體主要的業(yè)務流程i

23、nt serversd; /socket文件描述符,全局的struct sockaddr_in sndaddr; /組播地址/發(fā)送端的各種默認配置,都在server_conf.h以及proto.h中定義,struct server_conf_st server_conf = .rcvport = DEFAULT_RCVPORT, /端口 .mgroup = DEFAULT_MGROUP, /組播ip .media_dir = DEFAULT_MEDIADIR, /媒體目錄 .ifname = DEFAULT_IF, /網卡名'eth0' .runmode = run_daemo

24、n /守護進程;主要的業(yè)務流程1. 首先是設置日志文件2. 讀取命令行參數(shù),修改相應的server_conf的值3. 是否變成守護進程4. socket環(huán)境初始化,創(chuàng)建socket文件,UPD,組播地址,端口號,端口可復用,5. 獲取加載媒體資源,得到菜單列表, mlib_getchnlist6. 創(chuàng)建發(fā)送菜單的線程7. 循環(huán)創(chuàng)建發(fā)送各個頻道數(shù)據的線程8. 主線程暫定,由各個線程向組播地址發(fā)送數(shù)據,等待信號終止程序新遇到的函數(shù)或用法守護進程需要設置信號捕捉函數(shù),以便結束進程是不會丟失文件或數(shù)據/系統(tǒng)提供的日志記錄接口,相應日志記錄到系統(tǒng)的日志文件中去#include <syslog.h> void openlog(const char *ident, int option, int facility); /程序名稱,

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論