搭建简易直播服务
in 服务器 with 0 comment

搭建简易直播服务

in 服务器 with 0 comment

环境

相关软件:Nginx + ffmpeg + java + html
系统:虚拟机CentOs7
IP:192.168.0.163
测试方便关闭防火墙systemctl stop firewalld

安装nginx

按照正常安装nginx就行,但在编译的时候需要加入rtmp模块。安装nginx看这里

下载nginx-rtmp模块

git clone git://github.com/arut/nginx-rtmp-module.git

我都放在了/usr/local/src目录下,目录结构为

[root@localhost src]# pwd
/usr/local/src
[root@localhost src]# ll
drwxr-xr-x. 9 1001 1001      186 Jun 30 06:41 nginx-1.18.0
-rw-r--r--. 1 root root  1039530 Apr 21 10:33 nginx-1.18.0.tar.gz
drwxr-xr-x. 7 root root     4096 Jun 30 06:43 nginx-rtmp-module

安装nginx

编译时添加rtmp模块。
进入nginx-1.18.0目录,执行编译

./configure --with-http_ssl_module --with-http_v2_module --add-module=../nginx-rtmp-module && make && make install

顺手加了ssl模块和http2模块,视情况自己修改。

安装ffmpeg

步骤地址:https://www.vultr.com/docs/how-to-install-ffmpeg-on-centos,这里简单翻译记录。

更新系统

sudo yum install epel-release -y
sudo yum update -y
sudo shutdown -r now

安装Nux Dextop YUM存储库

目前没有CentOS的官方FFmpeg rpm软件包。相反,您可以使用第三方YUM存储库Nux Dextop来完成工作。在CentOS 7上,可以使用以下命令安装Nux Dextop YUM存储库:

sudo rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
sudo rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm

安装FFmpeg

sudo yum install ffmpeg ffmpeg-devel -y

测试

直接输入命令ffmpeg,输出一堆内容就是安装成功了。

配置nginx

打开nginx配置文件,加入两部分。

加入rtmp服务

放在最外层,和http服务同级。
这里配置了rtmp和hls两种直播流

rtmp{
    server{
        listen 1935;
        chunk_size 4000;
        
        # RTMP 直播流
        application rtmplive{
            live on;
            max_connections 1024;
        }
        
        # hls 直播流
        application hls{
            live on;
            hls on;
            hls_path /usr/local/var/www/hls;
            hls_fragment 5s;
        }
    }    
}

配置http转发hls直播流

在http服务的server里面加入hls的转发。

        location /hls {
            types{
                application/vnd.apple.mpegurl m3u8;
                video/mp2t ts;
            }
            root   /usr/local/var/www;
            add_header Cache-Control no-cache;
        }

修改配置后记得重启nginx

/usr/local/nginx/sbin/nginx -s reload

vlc播放器下载

官网下载地址:https://www.videolan.org

直播推流

准备一个mp4文件,重命名为test.mp4,进入到mp4文件所在目录,使用ffmpeg推流。

rtmp直播流

ffmpeg -re -i test.mp4 -vcodec libx264 -acodec aac -f flv -strict -2 rtmp://localhost:1935/rtmplive/rtmp

用VLC播放器,打开网络串流,输入直播地址:rtmp://192.168.0.163:1935/rtmplive/rtmp

hls直播流

ffmpeg -re -i test.mp4 -vcodec libx264 -acodec aac -f flv -strict -2 rtmp://localhost:1935/hls/stream

用VLC播放器,打开网络串流,输入直播地址:http://192.168.0.163/hls/stream.m3u8

windows用java推送直播流

maven依赖

        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>1.5.3</version>
        </dependency>

代码

package com.axon.video;

import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;
import org.bytedeco.opencv.opencv_core.IplImage;

import javax.swing.*;

/**
 * @Author: vision
 * @CreateDate: 2020/7/1 16:59
 * @Version: 1.0
 * @Copyright: Copyright (c) 2020
 * @Description:
 */
public class Video {
    public static void main(String[] args) throws Exception, InterruptedException, FrameRecorder.Exception {
        //(http://www.ossrs.net/players/srs_player.html)这个网站可以在线测试,不用自己部署推流服务器
        //推流服务器的地址
        recordCamera("rtmp://192.168.0.163:1935/hls/stream", 25);
    }

    public static void recordCamera(String outputFile, double frameRate)
            throws Exception {
        // 0代表的是第一个摄像头,如果是笔记本外接的usb摄像头时应该改为1,以此类推
        // 这里使用javacv的抓取器,至于使用的是ffmpeg还是opencv,请自行查看源码
        FrameGrabber grabber = FrameGrabber.createDefault(0);
        // 开启抓取器
        grabber.start();

        // 转换器
        OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
        // 抓取一帧视频并将其转换为图像,至于用这个图像用来做什么?加水印,人脸识别等等自行添加
        IplImage grabbedImage = converter.convert(grabber.grab());
        int width = grabbedImage.width();
        int height = grabbedImage.height();

        FrameRecorder recorder = FrameRecorder.createDefault(outputFile, width, height);
        // avcodec.AV_CODEC_ID_H264,编码
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
        // 封装格式,如果是推送到rtmp就必须是flv封装格式
        recorder.setFormat("flv");
        recorder.setFrameRate(frameRate);

        recorder.start();// 开启录制器
        long startTime = 0;
        long videoTS;
        CanvasFrame frame = new CanvasFrame("camera", CanvasFrame.getDefaultGamma() / grabber.getGamma());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setAlwaysOnTop(true);
        // 不知道为什么这里不做转换就不能推到rtmp
        Frame rotatedFrame;
        while (frame.isVisible() && (grabbedImage = converter.convert(grabber.grab())) != null) {
            rotatedFrame = converter.convert(grabbedImage);
            frame.showImage(rotatedFrame);
            if (startTime == 0) {
                startTime = System.currentTimeMillis();
            }
            videoTS = 1000 * (System.currentTimeMillis() - startTime);
            recorder.setTimestamp(videoTS);
            recorder.record(rotatedFrame);
            Thread.sleep(40);
        }
        frame.dispose();
        recorder.stop();
        recorder.release();
        grabber.stop();
    }
}

web端展示

引用video.js

github地址:https://github.com/videojs/video.js
官网地址:https://videojs.com
插件地址:https://videojs.com/plugins/
这里还要个插件解析直播流:https://www.npmjs.com/package/@hola.org/videojs-contrib-hls

示例代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link href="video-js.min.css" rel="stylesheet">
    <script src="video.min.js"></script>
    <script src="videojs-contrib-hls.min.js"></script>
</head>
<body>
    <video id="my-player" class="video-js" controls preload="auto" >
        <source src="http://192.168.0.163/hls/stream.m3u8" type="application/x-mpegURL">
        <p class="vjs-no-js">
            To view this video please enable JavaScript, and consider upgrading to a
            web browser that
        </p>
    </video>
<script>
    var player = videojs('my-player', {
    }, function onPlayerReady() {
        videojs.log('Your player is ready!');

        // In this context, `this` is the player that was created by Video.js.
        this.play();

        // How about an event listener?
        this.on('ended', function() {
            videojs.log('Awww...over so soon?!');
        });
    });
</script>
</body>
</html>

最后

一套下来能够运行,只是简单的推流与拉流,深入的话应该还有很多坑要踩。目前直播流大概10秒生成一个ts文件,所以直播可能有10多秒的延迟,应该在配置上可以进行优化。

Responses