最近用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块...还想吐很多学校的槽(最后还是忍住了,肯定还有很多更糟糕的学校,自我安慰下)

posted on 2015-08-31 16:39  wchrt  阅读(3174)  评论(3编辑  收藏  举报