輕松實現 網絡視頻播放器


  最近用activeX media player做了個播放器,做過的人都知道,幾乎沒技術含量。在自己無聊的玩弄中,發現這個控件能夠解析http、ftp協議,播放互聯網的文件資源。現在被困在學校也無事可做,干脆把給這播放器寫個服務器,用來播放互聯網上的公開資源。

  media player的activeX控件十分強大,只需設置正確的url即可播放本地乃至互聯網的文件資源。因此要給播放器做服務端,最重要的是向客戶端傳達正確的URL的信息。做服務器的思路便是:通過數據庫記錄下所有文件資源的信息與url,服務端讀取這些信息通過列表的形式發送給客戶端。客戶端將這些信息呈現給用戶,又用戶選擇播放的文件,之后將相應的url傳達給播放控件,由播放控件自動向url對應的服務器發起文件請求實現播放。

  綜上所述,服務端只需要完成數據庫存儲,與客戶端傳輸文件信息,以及與播放器傳輸文件數據即可。為了簡化開發,我們這里的文件傳輸暫時先采用apache這些http服務器,這樣也便於更早的調試。

  數據庫使用的mysql,服務器使用linux下的c++ socket epoll(其實使用php或是javaweb更方便,但我更想多用用c++)。客戶端使用的mfc+ActiveX。

 

  雖然服務器的實現很簡單,但客戶端更簡單,我先從最簡單的客戶端說起:

  有段時間沒摸過vs了,上次使用還是在擼cocos2d的時候。得意與強大的vs和activeX,一個能播放視頻的播放器只用了10幾分鍾就做好了,剩下的時間全花在播放控制與播放列表存儲與管理上。

  

  因為用的是vs2012,似乎並沒有該activeX的doc,於是自己在網上下載的CWMPPlayer4這些doc。

  可以通過輸入url直接播放該地址文件。

  簡單而強大,不單單能播放本地與自己服務器的視頻。但mkv這些視頻格式需要另寫解碼器,一些其他協議的網絡視頻需要作額外的處理。客戶端的介紹就這么點,真的沒再多了,另外只有關於鏈接服務器的部分。

 

  視頻信息服務器:

  首先是數據庫的設計,目前就一張表:

name type
id int
created_at timestap
updated_at timestap
type int
fileurl string
imgurl string
info text

  其中有個imgurl用於指向視頻介紹的截圖,用於用戶參看。

  因為服務的部分也沒太復雜或繁雜的地方,也就沒做什么設計,直接在自己以前封裝的epoll模型接口上開始寫服務邏輯。

  首先是數據庫通信,這里使用的自己以前封裝的數據庫類sqluse,添加上這次的查詢格式:

  

  模型:

 1 #define data_statu_end     0
 2 #define data_statu_wait    1
 3 #define data_statu_rewait  2
 4 #define data_statu_error   3
 5 #define data_statu_run     4
 6 
 7 #define data_type_unkonw   0
 8 
 9 struct model_filelist
10 {
11     int id;
12     string created_at;
13     string updated_at;
14     string name;
15     string info;
16     string imageurl;
17     string fileurl;
18     int type;
19 };

然后是協議文件:

 1 #ifndef _PROTO_H_
 2 #define _PROTO_H_
 3 
 4 
 5 #define QUEST_GET_LIST    100
 6 #define QUEST_GET_ONE     200
 7 
 8 #define RQUEST_ERROR     1000
 9 #define RQUEST_GET_LIST  1100
10 #define RQUEST_GET_ONE   1200
11 
12 
13 #define LIST_MAX_NUM 200
14 
15 struct proto_base
16 {
17     unsigned short quest;
18     unsigned long long sign;
19 };
20 
21 struct proto_filelist
22 {
23     int id;
24     char created_at[32];
25     char updated_at[32];
26     char name[64];
27     char info[256];
28     char imageurl[128];
29     char fileurl[128];
30     int type;
31 };
32 
33 struct proto_filelist_id
34 {
35     int num;
36     unsigned int idarr[LIST_MAX_NUM];
37 };
38 
39 #endif // _PROTO_H_

  因為封裝的epoll模型網絡部分和服務邏輯部分耦合較低,因此還是只通過那一個接口就能聯系到網絡部分與邏輯部分:

  

 1 #ifndef _MPLAYERSERVER_H_
 2 #define _MPLAYERSERVER_H_
 3 
 4 #include "include/sqluse.h"
 5 #include "include/proto.h"
 6 #include "include/ssock.h"
 7 
 8 
 9 class mplayerserver
10 {
11     sqluse sql;
12 public:
13     mplayerserver();
14     ~mplayerserver();
15 
16     mdata *dealdata(mdata *data);//the only api
17 
18 };
19 
20 #endif //_MPLAYERSERVER_H_

 

  最后就是服務器處理數據的邏輯:

 1 mdata *mplayerserver::dealdata(mdata *data)
 2 {
 3     mdata *newdata=new mdata;
 4     newdata->fd=data->fd;
 5 
 6     proto_base rebase;
 7 
 8     proto_base *basedata=(proto_base *)data->buf;
 9 
10     if(basedata->quest==QUEST_GET_LIST)
11     {
12         proto_filelist_id re;
13         re.num=sql.getfilelistid(re.idarr,sizeof(re.idarr));
14         if(re.num>0)
15         {
16             rebase.quest=RQUEST_GET_LIST;
17             newdata->adddata((char *)&rebase,sizeof(rebase));
18             newdata->adddata((char *)&re,sizeof(re));
19         }
20         else
21         {
22             failmdata(newdata);
23         }
24 
25     }
26     else if(basedata->quest==QUEST_GET_ONE)
27     {
28         unsigned long filelistid=basedata->sign;
29 
30         model_filelist mlist;
31         mlist.id=filelistid;
32         if(sql.getonefilelist(&mlist))
33         {
34             proto_filelist re;
35             re.id=mlist.id;
36             strcpy(re.created_at,mlist.created_at.c_str());
37             strcpy(re.updated_at,mlist.updated_at.c_str());
38             strcpy(re.name,mlist.name.c_str());
39             strcpy(re.info,mlist.info.c_str());
40             strcpy(re.imageurl,mlist.imageurl.c_str());
41             strcpy(re.fileurl,mlist.fileurl.c_str());
42             re.type=mlist.type;
43 
44             rebase.quest=RQUEST_GET_ONE;
45             newdata->adddata((char *)&rebase,sizeof(rebase));
46             newdata->adddata((char *)&re,sizeof(re));
47         }
48         else
49         {
50             failmdata(newdata);
51         }
52     }
53   //more quest..
54 
55     return newdata;
56 }

客戶端連接服務器后獲取到網絡視頻列表:

  視頻數據傳送:

  這里采用的是apache服務器來進行文件傳送,通過url導向Apache所在服務器以及文件結構下的視頻文件,來實現視頻文件傳輸與播放。這部分以后可以自己用http協議或者是public ftp實現。

   

  一套能用的網絡播放器就做好,非常的簡單。

  但是這樣的播放器還是不能滿足現代視頻播放的需要的。因為版權與利益的問題,網絡上的大量視頻都經過加密、路由轉換等手段使得其他終端不能輕易的獲取與播放,再加之目前的很多視頻在容量上有很大的壓縮空間,可以通過一些優化的算法與協議對傳輸的視頻數據進行處理,實現視頻的高效傳輸。我因為經歷有限,也不想在這方面深入下去。希望自己這微不足道的網絡播放器制作經歷對大家有點幫助。

 

  筆者都大四該出去實習了,學校逼着留校實訓竟然還是讓做視頻播放器,而且是2人一組使用mfc activeX做一個本地視頻播放器,服務端都還是自己主動做的。一共要求做一個月,每天都要寫進度文檔,666,最多一天就做完的東西,剩下的29天進度文檔就要靠想象力。雖然是個本科,但待這學校里面除了靠自己,真學不到任何東西,要出去實習只能去給過學校好處的單位,已經有朋友去其他單位被強制弄回來或是給處分了。系領導是個當兵的,根本就不知道什么是道理與邏輯,自己說什么就是什么。學校一瓢葷菜8塊素材4塊...還想吐很多學校的槽(最后還是忍住了,肯定還有很多更糟糕的學校,自我安慰下)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM