zoukankan      html  css  js  c++  java
  • 流媒体

    一,什么是流媒体

    我们这里采用录播第三种技术方案:

    点播和直播两种方式,我们先调研点播的方案,如下:

    1、 播放器通过 http协议从http服务器上下载视频文件进行播放

    问题:必须等到视频下载完才可以播放,不支持快进到某个时间点进行播放

    2、 播放器通过rtmp协议连接媒体服务器以实时流方式播放视频

    使用rtmp协议需要架设媒体服务器,造价高,对于直播多采用此方案。

    3、 播放器使用HLS协议连接http服务器(Nginx、Apache tomcat等)实现近实时流方式播放视频

    HLS协议:将一个视频通过一个解码器(ffmeg)转换为一个编码格式为m3u8文件(装很多ts文件的索引信息)和若干个ts文件列表,用户只用下载M3u8文件,然后可以实现视频播放和跳转(快进快退)。

    MP4,rmvb,avi是文件格式

    H264是视频的编码格式

    视频上传到专门的服务器上然后下载,流媒体就是将视频文件分成许多小块儿,将这些小块儿作为数据包通过网络发送出去,实现一边传输视频 数据 包一边观看视频

    二,ffmeg转码方式

    (一)使用ffmeg生成m3u8的步骤

    先将avi转换为MP4

    ffmpeg.exe -i  lucene.avi -c:v libx264 -s 1280x720 -pix_fmt yuv420p -b:a 63k -b:v 753k -r 18 .lucene.mp4

    (二)再将MP4生成M3u8

    ffmpeg -i  lucene.mp4   -hls_time 10 -hls_list_size 0  -hls_segment_filename ./hls/lucene_%05d.ts ./hls/lucene.m3u8

    生成了一个M3U8文件和ts文件类表。

    三。视频播放器

    技术选型:(选H5)

    flash播放器:缺点是需要在客户机安装Adobe Flash Player播放器,优点是flash播放器已经很成熟了,并且浏览器对flash支持也很好。

    H5播放器:基于h5自带video标签进行构建,优点是大部分浏览器支持H5,不用再安装第三方的flash播放器,并且随着前端技术的发展,h5技术会越来越成熟。

    本项目采用H5播放器,使用Video.js开源播放器。

    ​ Video.js是一款基于HTML5世界的网络视频播放器。它支持HTML5和Flash视频,它支持在台式机和移动设备上播放视频。这个项目于2010年中开始,目前已在40万网站使用。

    官方地址:http://videojs.com/

    2搭建媒体服务器

    nginx的config的代理转发:

    www.XXX/video(其中的proxy代理路径)的,根据proxy的路径找到upstream(其中的127.0.0.1的90端口),再根据90端口找到本地的保存视频的文件夹。

    四,项目中的运用

    (一)总体框架

    老师通过视频管理系统前端上传视频到媒资管理系统,媒资管理系统将媒资描述性信息保存在mongoDB中(比如文件名称,文件路径),同时上传到指定的视频服务器。

    课程管理服务需要从媒资管理系统中检索到媒资信息,并完成媒资信息和课程计划的绑定,然后存在mysql中,

    学生访问学习中心前端,点击课程计划三级目录中视频播放,请求学习服务,学习服务查询媒资信息,通过代理转发播放视频。

    (二)断点续传

    原理:将文件拆成若干个小文件,分块上传,然后全部分块上传完毕后,进行文件的合并。

    (三)视频处理

    视频处理进程的任务是接收视频处理消息进行视频处理,业务流程如下:

    1、监听MQ,接收视频处理消息。

    2、进行视频处理。

    3、向数据库写入视频处理结果。

    视频处理进程属于媒资管理系统的一部分,考虑提高系统的扩展性,将视频处理单独定义视频处理工程。

    通过processbuilder调用执行外部命令。

    MP4utils将avi转换MP4

    hlsvideoutils生成M3u8和ts文件列表。

    将相对应的信息保存在mongodb中

      1 @Component
      2 public class MediaProcessConsumer {
      3 
      4     @Autowired
      5     private MediaFileRepository mediaFileRepository;
      6 //xc-service-manage-media.ffmpeg-path
      7     @Value("${xc-service-manage-media.ffmpeg-path}")
      8     private String ffmpegPath;
      9 
     10     @Value("${xc-service-manage-media.video-location}")
     11     private String videoLocation;
     12 
     13 
     14     @RabbitListener(queues = {"${xc-service-manage-media.mq.queue-media-video-processor}"})
     15     public void receiveMediaMessage(String message){
     16         // message :  {"mediaId","4848rdgdfg"}
     17 
     18         //转换消息
     19         Map map = JSON.parseObject(message, Map.class);
     20         String mediaId = (String) map.get("mediaId");
     21 
     22         //查询mediafile对象信息
     23         Optional<MediaFile> mediaFileOptional = mediaFileRepository.findById(mediaId);
     24         if (!mediaFileOptional.isPresent()){
     25             return;
     26         }
     27         MediaFile mediaFile = mediaFileOptional.get();
     28 
     29         //当前操作的文件类型必须是avi
     30         String fileType = mediaFile.getFileType();
     31         if (fileType == null || !"avi".equals(fileType)){
     32             mediaFile.setProcessStatus("303004"); //无需处理
     33             mediaFileRepository.save(mediaFile);
     34             return;
     35         }else{
     36             mediaFile.setProcessStatus("303001");
     37             mediaFileRepository.save(mediaFile);
     38         }
     39 
     40         //将avi转成MP4
     41         /**
     42          * String ffmpeg_path,
     43          * String video_path, :被转换的文件位置
     44          * String mp4_name,: 生成的mp4文件名称
     45          * String mp4folder_path: MP4存储的路径
     46          */
     47         String video_path =videoLocation+mediaFile.getFilePath()+mediaFile.getFileName();
     48         String mp4_name = mediaFile.getFileId()+".mp4";
     49         String mp4folder_path = videoLocation+mediaFile.getFilePath();
     50 
     51         Mp4VideoUtil mp4VideoUtil = new Mp4VideoUtil(ffmpegPath,video_path,mp4_name,mp4folder_path);
     52 
     53         String result = mp4VideoUtil.generateMp4();
     54 
     55         if (result == null || !"success".equals(result)){
     56             //转换失败
     57             mediaFile.setProcessStatus("303003");
     58             MediaFileProcess_m3u8 mediaFileProcess_m3u8 = new MediaFileProcess_m3u8();
     59             mediaFileProcess_m3u8.setErrormsg(result);
     60             mediaFile.setMediaFileProcess_m3u8(mediaFileProcess_m3u8);
     61 
     62             mediaFileRepository.save(mediaFile);
     63             return;
     64         }
     65 
     66 
     67         //将mp4转成ts文件列表 & .m3u8文件
     68         /**
     69          * String ffmpeg_path,
     70          * String video_path,:被转换的mp4文件的路径
     71          * String m3u8_name,: m3u8文件名称
     72          * String m3u8folder_path: 保存m3u8文件与ts文件列表的文件夹路径
     73          */
     74         String MP4_video_path =videoLocation+mediaFile.getFilePath()+mp4_name;
     75         String m3u8_name = mediaFile.getFileId()+".m3u8";
     76         String m3u8folder_path = videoLocation+mediaFile.getFilePath()+"hls/";
     77 
     78         HlsVideoUtil hlsVideoUtil = new HlsVideoUtil(ffmpegPath,MP4_video_path,m3u8_name,m3u8folder_path);
     79 
     80         String m3u8Result = hlsVideoUtil.generateM3u8();
     81         if (m3u8Result == null || !"success".equals(m3u8Result)){
     82             //转换失败
     83             mediaFile.setProcessStatus("303003");
     84             MediaFileProcess_m3u8 mediaFileProcess_m3u8 = new MediaFileProcess_m3u8();
     85             mediaFileProcess_m3u8.setErrormsg(result);
     86             mediaFile.setMediaFileProcess_m3u8(mediaFileProcess_m3u8);
     87 
     88             mediaFileRepository.save(mediaFile);
     89             return;
     90         }
     91 
     92         //将信息保存到mongo
     93 
     94         MediaFileProcess_m3u8 mediaFileProcess_m3u8 = new MediaFileProcess_m3u8();
     95         mediaFileProcess_m3u8.setTslist(hlsVideoUtil.get_ts_list());
     96 
     97         mediaFile.setMediaFileProcess_m3u8(mediaFileProcess_m3u8);
     98 
     99         mediaFile.setProcessStatus("303002");
    100 
    101         //保存m3u8文件路径
    102         mediaFile.setFileUrl(mediaFile.getFilePath()+"hls/"+m3u8_name);
    103 
    104         mediaFileRepository.save(mediaFile);
    105     }
    106 }

    消费者

    当一个男人不再对你啰嗦,不再缠着你,不再没事找你,对你说话也客气了,也不再气你了。那么恭喜你,你已经成功的失去了他。别嫌弃男人幼稚,那是他喜欢你,爱你。女人说男人像小孩子一样不成熟,可又有谁知道,男人在自己喜欢的女人面前才像小孩子,如果不喜欢你了,不爱你了,他比你爸还成熟。
  • 相关阅读:
    三大高级排序
    三大初级排序算法
    MVC的JsonResult用法
    使用dynamic类型改进反射
    正则指引-括号(3)反向引用
    正则指引-括号(2)引用分组
    正则指引-括号(1)
    正则指引-量词demo
    正则指引-字符组demo
    ASP.NET MVC 分部视图
  • 原文地址:https://www.cnblogs.com/fengtangjiang/p/11129337.html
Copyright © 2011-2022 走看看