一、阿里云视频直播

1、什么是视频直播

视频直播服务(ApsaraVideo Live)是基于领先的内容接入、分发网络和大规模分布式实时转码技术打造的音视频直播平台,提供便捷接入、高清流畅、低延迟、高并发的音视频直播服务。

2、视频直播架构

在这里插入图片描述

  • 主播通过采集设备采集直播内容后,通过推流SDK推送直播流,视频直播服务通过边缘推流的方式将直播流推送至阿里云直播中心,推送的视频流通过CDN边缘节点进行加速保证上行传输的稳定性。

  • 视频流推送至阿里云直播中心后,可按需对视频流进行转码、时移、录制、截图等处理。

  • 处理好的视频流通过CDN内容分发网络,下发至观众的设备中进行播放。移动端的播放设备可以集成阿里云提供的播放器SDK进行开发。

  • 直播视频除了可以进行转码截图等操作外,还可以进行直播转点播的操作,将录制下来的视频转至点播系统中再进行点播播放和短视频云剪辑。方便直播与短视频内容生产和传播的联动。

3、官方文档链接

视频直播官方开发文档

二、使用流程

1、使用条件
  • 已有阿里云账号
  • 账号已经实名认证
  • 准备好2个已完成备案的域名
  • 开通视频直播服务
2、添加推流域名和播流域名

进入直播控制台,点击域名管理,添加域名

在这里插入图片描述

  • 首先添加推流域名,业务类型选择推流域名

加速域名填子域名,就是在域名前加上一个随机前缀play,如 play.xxx.com,域名解析地址为xxx.com

在这里插入图片描述

  • 这里进行DNS解析验证,去解析域名,添加记录
    在这里插入图片描述
  • 选择对应的域名,点击解析域名
    在这里插入图片描述
  • 点击添加记录
    在这里插入图片描述
  • 将需要验证的信息填到这里

记录类型:TXT
主机记录:verification
记录值:verify_xxxxxxxxxxxxxxxxxxxxxx

在这里插入图片描述

  • 添加添加记录后,这里点击验证
    在这里插入图片描述
  • 如图所示对应的加速域名添加成功
    在这里插入图片描述
  • 然后添加播流域名,业务类型选择播流域名,其他同上

在这里插入图片描述

3、配置CNAME
  • 这里将记录值复制下来
    在这里插入图片描述

  • 在域名解析这里添加记录,记录类型选择CNAME,记录值为刚刚加速域名添加的随机前缀

我这里播流域名为 play.xxx.com,即为play
推流域名为 push.xxx.com,即为push,
然后将对应的记录值粘贴过来即可

在这里插入图片描述

  • 刚开始会显示配置中,如图所示配置成功
    在这里插入图片描述
4、关联推流域名和播流域名
  • 选择一个播流域名,单击域名配置

在这里插入图片描述

  • 选择推流信息一栏,点击添加推流信息
    在这里插入图片描述
  • 选择推流域名,点击确定保存
    在这里插入图片描述
5、生成推流地址和播放地址
  • 选择工具箱,点击地址生成器
  • 选择播流域名和推流域名
  • AppName:随便填
  • StringName:随便填(如0000)

在这里插入图片描述

  • 生成地址示例如下:
    在这里插入图片描述
6、开始测试推流和播流

在这里插入图片描述

  • 打开OBS,选择文件,打开设置
    在这里插入图片描述
  • 服务:自定义
  • 推流地址例子:rtmp://push.aliyunlive.com/app/stream?auth_key=1543302081-0-0-9c6e7c8190c10bdfb3c0xxxxxx
  • 服务器:rtmp://push.aliyunlive.com/app/
  • 串流密钥:stream?auth_key=1543302081-0-0-9c6e7c8190c10bdfb3c0xxxxxx(以AppName为分割)

在这里插入图片描述

  • 点击+号,选择视频采集设备

若想传本地视频,可以选择媒体源,打开选择一个mp4格式的视频文件即可

在这里插入图片描述

  • 创建好后,确定保存
    在这里插入图片描述
  • 右下方控件,点击开始推流
    在这里插入图片描述
  • 打开 VLC,选择媒体,单击打开网络串流
    在这里插入图片描述
  • 此处以FLV播流地址为例
    在这里插入图片描述
  • 将播流地址粘贴到网络 URL处
    在这里插入图片描述
  • 效果如下

右边OBS通过推流,将摄像头的画面推送出去,左侧VLC通过播流地址播放实时播放画面

在这里插入图片描述

三、Java实现推流和播流地址生成

1、添加依赖
     <!-- Hutool工具包 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.0.12</version>
        </dependency>
     <!-- aliyun 核心sdk-->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>4.5.1</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.10.2</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-vod</artifactId>
            <version>2.15.11</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.28</version>
        </dependency>
        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20170516</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.2</version>
        </dependency>
2、配置application.properties
#阿里云直播配置
#推流域名
live.push.domain=xxx
#推流鉴权url key
live.push.ident.key=xxx
#拉流域名
live.pull.domain=xxx
#拉流鉴权url key
live.pull.ident.key=xxx
#直播测试appName
live.appName=xxx
#直播测试streamName{直播类型}{类型id}
live.streamName=xxx
#鉴权url的有效时间(秒),默认30分钟,1800秒
live.ident.url.validTime=1800

推流域名:前面的生成的push.xxx.com
播流(拉流)域名:前面的生成的pull.xxx.com
推流鉴权url key:点击域名管理,域名配置,访问控制,url鉴权查看key
播流鉴权url key:同上,选择播流域名查看
appName:自定义
streamName:自定义(前端传参就是sourceId,就是根据这streamName(sourceId)生成不同的直播房间,推流地址)

在这里插入图片描述
在这里插入图片描述

3、创建LIveConfig
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.Serializable;

@Component
public class LiveConfig implements Serializable {

    /**
     * 推流域名
     */
    @Value("${live.push.domain}")
    private String livePushDomain;

    /**
     * 拉流域名
     */
    @Value("${live.pull.domain}")
    private String livePullDomain;

    /**
     * 直播测试appName
     */
    @Value("${live.appName}")
    private String liveAppName;

    /**
     * 直播测试streamName{直播类型}_{类型id}
     */
//    @Value("${live.streamName}")
//    private String liveStreamName;

    /**
     * 推流鉴权url key
     */
    @Value("${live.push.ident.key}")
    private String livePushIdentKey;

    /**
     * 拉流鉴权url key
     */
    @Value("${live.pull.ident.key}")
    private String livePullIdentKey;

    /**
     * 鉴权url的有效时间(秒),默认30分钟,1800秒 key
     */
    @Value("${live.ident.url.validTime}")
    private Integer liveIdentUrlValidTime;

    public String getLivePushDomain() {
        return livePushDomain;
    }

    public void setLivePushDomain(String livePushDomain) {
        this.livePushDomain = livePushDomain;
    }

    public String getLivePullDomain() {
        return livePullDomain;
    }

    public void setLivePullDomain(String livePullDomain) {
        this.livePullDomain = livePullDomain;
    }

    public String getLiveAppName() {
        return liveAppName;
    }

    public void setLiveAppName(String liveAppName) {
        this.liveAppName = liveAppName;
    }

    public String getLivePushIdentKey() {
        return livePushIdentKey;
    }

    public void setLivePushIdentKey(String livePushIdentKey) {
        this.livePushIdentKey = livePushIdentKey;
    }

    public String getLivePullIdentKey() {
        return livePullIdentKey;
    }

    public void setLivePullIdentKey(String livePullIdentKey) {
        this.livePullIdentKey = livePullIdentKey;
    }

    public Integer getLiveIdentUrlValidTime() {
        return liveIdentUrlValidTime;
    }

    public void setLiveIdentUrlValidTime(Integer liveIdentUrlValidTime) {
        this.liveIdentUrlValidTime = liveIdentUrlValidTime;
    }
}

4、创建LiveUtil
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LiveUtil {
    private static final Logger log = LoggerFactory.getLogger(LiveUtil.class);
    /**
     * 推拉流地址示例:
     * rtmp://www.ttest.ygdjonline.com/a/a?auth_key=1558065152-0-0-c3cb54d946c0590ca9aeee63573201ee
     * 播流地址
     * 原画
     * rtmp://www.btest.ygdjonline.com/a/a?auth_key=1558065152-0-0-fc711455c0815aeb581385f33451d5b4
     * http://www.btest.ygdjonline.com/a/a.flv?auth_key=1558065152-0-0-221abff1da1ee32151e365cf0dd42a53
     * http://www.btest.ygdjonline.com/a/a.m3u8?auth_key=1558065152-0-0-72124fcc3aee3404b0d65dcc114e207f
     */

    /**
     * 根据源id创建该id的推流url
     *
     * @param sourceId
     * @param liveConfig
     * @return
     */
    public static String createPushUrl(String sourceId, LiveConfig liveConfig) {

        // 推流域名
        String pushDomain = liveConfig.getLivePushDomain();
        // 应用名称
        String appName = liveConfig.getLiveAppName();
        // 流名称
        String streamName = StrUtil.format(sourceId);
        // 推流签名key
        String pushIdentKey = liveConfig.getLivePushIdentKey();
        // 签名url有效时间
        Integer identUrlValidTime = liveConfig.getLiveIdentUrlValidTime();
        //log.info("签名url有效时间" + identUrlValidTime);
        // 计算过期时间
        String timestamp = String.valueOf((System.currentTimeMillis() / 1000) + identUrlValidTime);
        // log.info("计算过期时间" + timestamp);
        // 组合推流域名前缀
        //rtmp://{pushDomain}/{appName}/{streamName}
        String rtmpUrl = StrUtil.format("rtmp://{}/{}/{}", pushDomain, appName, streamName);

        // 组合md5加密串
        ///{appName}/{streamName}-{timestamp}-0-0-{pushIdentKey}
        String md5Url = StrUtil.format("/{}/{}-{}-0-0-{}", appName, streamName, timestamp, pushIdentKey);
        log.info("组合md5加密串"+md5Url);
        // md5加密
        String md5Str = DigestUtil.md5Hex(md5Url);
        // log.info("md5加密串,md5Url=" + md5Url + "------md5加密结果,md5Str=" + md5Str);

        // 组合最终鉴权过的推流域名
//      {rtmpUrl}?auth_key={timestamp}-0-0-{md5Str}
        String finallyPushUrl = StrUtil.format("{}?auth_key={}-0-0-{}", rtmpUrl, timestamp, md5Str);
        log.info("最终鉴权过的推流域名=" + finallyPushUrl);

        return finallyPushUrl;
    }

    /**
     * 创建拉流域名,key=rtmpUrl、flvUrl、m3u8Url,代表三种拉流类型域名
     *
     * @param sourceId
     * @param liveConfig
     * @return
     */
    public static String createPullUrl(String sourceId, LiveConfig liveConfig) {

        // 拉流域名
        String pullDomain = liveConfig.getLivePullDomain();
        // 应用名称
        String appName = liveConfig.getLiveAppName();
        // 流名称
        String streamName = StrUtil.format(sourceId);
        // 拉流签名key
        String pullIdentKey = liveConfig.getLivePullIdentKey();
        // 签名url有效时间
        Integer identUrlValidTime = liveConfig.getLiveIdentUrlValidTime();

        // 计算过期时间
        String timestamp = String.valueOf((System.currentTimeMillis() / 1000) + identUrlValidTime);

        // 组合通用域名
//      {pullDomain}/{appName}/{streamName}
        String pullUrl = StrUtil.format("{}/{}/{}", pullDomain, appName, streamName);
        //log.info("组合通用域名,pullUrl=" + pullUrl);

        // 组合md5加密串
//      /{appName}/{streamName}-{timestamp}-0-0-{pullIdentKey}
        String md5Url = StrUtil.format("/{}/{}-{}-0-0-{}", appName, streamName, timestamp, pullIdentKey);
        String md5FlvUrl = StrUtil.format("/{}/{}.flv-{}-0-0-{}", appName, streamName, timestamp, pullIdentKey);
        String md5M3u8Url = StrUtil.format("/{}/{}.m3u8-{}-0-0-{}", appName, streamName, timestamp, pullIdentKey);

        // md5加密
        String md5Str = DigestUtil.md5Hex(md5Url);
        String md5FlvStr = DigestUtil.md5Hex(md5FlvUrl);
        String md5M3u8Str = DigestUtil.md5Hex(md5M3u8Url);
        //log.info("md5加密串,md5Url    =" + md5Url + "       ------     md5加密结果,md5Str=" + md5Str);
        //log.info("md5加密串,md5FlvUrl =" + md5FlvUrl + "    ------    md5加密结果,md5FlvStr=" + md5FlvStr);
        //log.info("md5加密串,md5M3u8Url=" + md5M3u8Url + "   ------    md5加密结果,md5M3u8Str=" + md5M3u8Str);

        // 组合三种拉流域名前缀
//        rtmp://{pullUrl}?auth_key={timestamp}-0-0-{md5Str}
        String rtmpUrl = StrUtil.format("rtmp://{}?auth_key={}-0-0-{}", pullUrl, timestamp, md5Str);
//        http://{pullUrl}.flv?auth_key={timestamp}-0-0-{md5FlvStr}
        String flvUrl = StrUtil.format("http://{}.flv?auth_key={}-0-0-{}", pullUrl, timestamp, md5FlvStr);
//        http://{pullUrl}.m3u8?auth_key={timestamp}-0-0-{md5M3u8Str}
        String m3u8Url = StrUtil.format("http://{}.m3u8?auth_key={}-0-0-{}", pullUrl, timestamp, md5M3u8Str);

        log.info("最终鉴权过的拉流rtmp域名=" + rtmpUrl);
        log.info("最终鉴权过的拉流flv域名 =" + flvUrl);
        log.info("最终鉴权过的拉流m3u8域名=" + m3u8Url);
        return flvUrl;
    }
}

5、创建LiveAddress
import java.io.Serializable;

public class LiveAddress implements Serializable {
    private String pushUrl;

    private String pullUrl;

    public String getPushUrl() {
        return pushUrl;
    }

    public void setPushUrl(String pushUrl) {
        this.pushUrl = pushUrl;
    }

    public String getPullUrl() {
        return pullUrl;
    }

    public void setPullUrl(String pullUrl) {
        this.pullUrl = pullUrl;
    }
}

6、创建LiveController
import com.dimpt.base.util.LiveConfig;
import com.dimpt.base.util.LiveUtil;
import com.dimpt.rest.model.LiveAddress;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/live")
public class LiveController {
    @Autowired
    private LiveConfig liveConfig;
    /**
     * 生成推流播流地址
     * sourceId  在这里我将它设置为房间号
     */
    @GetMapping("/save_Live")
    public LiveAddress save_Live(@RequestParam("sourceId") String sourceId){
        //生成推流地址
        String pushUrl = LiveUtil.createPushUrl(sourceId, liveConfig);
        //生成播流地址
        String pullUrl = LiveUtil.createPullUrl(sourceId, liveConfig);
        LiveAddress liveAddress = new LiveAddress();
        liveAddress.setPushUrl(pushUrl);
        liveAddress.setPullUrl(pullUrl);
        return liveAddress;
    }

}
7、测试运行

sourceId=任意值,推流播流地址就生成了

在这里插入图片描述
在这里插入图片描述
请添加图片描述

Logo

致力于链接即构和开发者,提供实时互动和元宇宙领域的前沿洞察、技术分享和丰富的开发者活动,共建实时互动世界。

更多推荐