• 轻松实现 网络视频播放器


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

  • 相关阅读:
    高并发的优化策略
    Linux Ctrl+c与ctrl+z的区别
    数据库连接池的工作原理
    JDBC数据库连接池原理
    JSP页面批量选择&全选操作&选择回显
    通过火狐谋智查询API
    通过console.log()打印window对象的属性、方法、事件
    制作 首页
    JavaScript 函数参数
    JavaScript 函数
  • 原文地址:https://www.cnblogs.com/wchrt/p/4772753.html
Copyright © 2020-2023  润新知