【OSS 排查方案-4】OSS + RTMP 推流的 JAVA 方法

本文涉及的产品
对象存储 OSS,标准 - 本地冗余存储 20GB 3个月
对象存储 OSS,内容安全 1000 次 1年
对象存储OSS,敏感数据保护2.0 200GB 1年
简介: 背景:目前有很多直播爱好者使用的是 OSS + RTMP 做的推流直播,其中不乏一些企业级别应用,由于 OSS 作为推流的接收略微有一些复杂,故单独开篇讲一下。其实不建议使用 OSS+RTMP 做直播推流,因为功能性相比专业的阿里云直播几乎为 0 ,而且性能上并不好。

背景:目前有很多直播爱好者使用的是 OSS + RTMP 做的推流直播,其中不乏一些企业级别应用,由于 OSS 作为推流的接收略微有一些复杂,故单独开篇讲一下。其实不建议使用 OSS+RTMP 做直播推流,因为功能性相比专业的阿里云直播产品来说,OSS 的推流适合监管备份等特定场景 ,客户端对直播推流的延迟要求不是很敏感。如果对直播的拉流推流延迟有高敏感的场景,建议大家使用单独的直播服务,特点,可以就近解决通过 CDN 的方式加速上行和下行的网络链路,具备多样化的功能。


首先:
看下官网对于 OSS 推流的过程定义

  • 只能使用RTMP推流的方式,不支持拉流。
  • 必须包含视频流,且视频流格式为H264。
  • 音频流是可选的,并且只支持AAC格式,其他格式的音频流会被丢弃。
  • 转储只支持HLS协议。
  • 一个LiveChannel同时只能有一个客户端向其推流。
RTMP 的推流格式:
rtmp://your-bucket.oss-cn-hangzhou.aliyuncs.com/live/test-channel
  • live 等同于 RTMP 的 APP 挂载点
  • test-channel 等同于 RTMP 的 stream name

RTMP URL 推流签名:

  • rtmp://${bucket}.${host}/live/${channel}?OSSAccessKeyId=xxx&Expires=yyy&Signature=zzz&${params}
  • 推流前 LiveChannel有两种Status:enabled和disabled,用户可以使用本接口在两种Status之间进行切换。处于disabled状态时,OSS会禁止用户向该LiveChannel进行推流操作;如果有用户正在向该LiveChannel推流,那么推流的客户端会被强制断开(可能会有10s左右的延迟)

我们现在用 java 的 SDK 演示一下如上的推理过程,在跑 SDK 之前,需要先搭建好一套本地的 eclipse 环境,如下是我用的 eclipse,如果有没搭建请网上搜索一下 eclpse 的搭建方式(之前需要安装 JDK 且配置环境变量)

  • Eclipse 版本:Version: Neon.3 Release (4.6.3)
  • JDK 版本:jdk1.8.0_144
  • OSS:公开读(为了验证推流功能是否正常,我们用公开读的方式快速测试)

我们采用主函数入口的方式,实例化其他类进行调用,这样方便类的拆分,不用都集合在主函数中。
主函数 domain,实例化 OSSClient 对象传入到 RtmpTest 类中测试。

所有的 jar 都会通过官方的 maven 解决的依赖关系,https://help.aliyun.com/document_detail/32009.html?spm=5176.doc32008.6.672.HR4Dbr


package javasdk;

import java.io.FileNotFoundException;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;

import com.aliyun.oss.OSSClient;

public class domain {
	public static void main( String[] args ) throws ParseException, FileNotFoundException
    {
    	
        System.out.println( "Hello World!" );
        String accessid = "AK";
        String secretkey = "SK";
        String objectpath = "C://Users//hanli.zyb//Desktop//running.png";
        String bucket = "bucket";
        String object = "running";
        String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";

        
        // OSS + rtmp 推流
        String bucketName = "ali-hangzhou";
        RtmpTest pushoss = new RtmpTest();
        OSSClient ossClient = new OSSClient(endpoint, AK, SK);
        pushoss.testCreateLiveChannel(bucketName,ossClient);

    }
}
​

RtmpTest



/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package javasdk;

import java.text.ParseException;
import java.util.Date;
import java.util.List;
import junit.framework.Assert;

import org.junit.Ignore;
import org.junit.Test;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSErrorCode;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.DateUtil;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.CreateLiveChannelRequest;
import com.aliyun.oss.model.CreateLiveChannelResult;
import com.aliyun.oss.model.ListLiveChannelsRequest;
import com.aliyun.oss.model.LiveChannel;
import com.aliyun.oss.model.LiveChannelInfo;
import com.aliyun.oss.model.LiveChannelListing;
import com.aliyun.oss.model.LiveChannelStat;
import com.aliyun.oss.model.LiveChannelStatus;
import com.aliyun.oss.model.LiveChannelTarget;
import com.aliyun.oss.model.LiveRecord;
import com.aliyun.oss.model.PushflowStatus;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;

/**
 * Test rtmp
 */
public class RtmpTest  {
	String bucketName = "bucket";
	final String liveChannel = "stream name";
    @Test
    public void testCreateLiveChannelDefault(String bucketname,OSSClient ossClient) {

        try {
            CreateLiveChannelRequest createLiveChannelRequest = new CreateLiveChannelRequest(
                    bucketName, liveChannel);
            CreateLiveChannelResult createLiveChannelResult = ossClient.createLiveChannel(createLiveChannelRequest);
            LiveChannelInfo liveChannelInfo = ossClient.getLiveChannelInfo(bucketName, liveChannel);

            
            ossClient.deleteLiveChannel(bucketName, liveChannel);
        } catch (Exception e) {
            Assert.fail(e.getMessage());
        }
    }
    
    @Test
    public void testCreateLiveChannel(String bucketname,OSSClient ossClient) {
        final String liveChannel = "normal-create-live-channel";
        final String liveChannelDesc = "my test live channel";

        try {
            LiveChannelTarget target = new LiveChannelTarget("HLS", 100, 99, "myplaylist.m3u8");
            CreateLiveChannelRequest createLiveChannelRequest = new CreateLiveChannelRequest(
                    bucketName, liveChannel, liveChannelDesc, LiveChannelStatus.Enabled, target);
            
            CreateLiveChannelResult createLiveChannelResult = ossClient.createLiveChannel(createLiveChannelRequest);
            System.out.println(createLiveChannelResult.getPublishUrls());
            /*Assert.assertEquals(createLiveChannelResult.getPublishUrls().size(), 1);
            Assert.assertTrue(createLiveChannelResult.getPublishUrls().get(0).startsWith("rtmp://"));
            Assert.assertTrue(createLiveChannelResult.getPublishUrls().get(0).endsWith("live/" + liveChannel));
            Assert.assertEquals(createLiveChannelResult.getPlayUrls().size(), 1);
            Assert.assertTrue(createLiveChannelResult.getPlayUrls().get(0).startsWith("http://"));
            Assert.assertTrue(createLiveChannelResult.getPlayUrls().get(0).endsWith(liveChannel + "/myplaylist.m3u8"));*/
            
           /* LiveChannelInfo liveChannelInfo = ossClient.getLiveChannelInfo(bucketName, liveChannel);
            Assert.assertEquals(liveChannelInfo.getDescription(), liveChannelDesc);
            Assert.assertEquals(liveChannelInfo.getStatus(), LiveChannelStatus.Disabled);
            Assert.assertEquals(liveChannelInfo.getTarget().getType(), "HLS");
            Assert.assertEquals(liveChannelInfo.getTarget().getFragDuration(), 100);
            Assert.assertEquals(liveChannelInfo.getTarget().getFragCount(), 99);
            Assert.assertEquals(liveChannelInfo.getTarget().getPlaylistName(), "myplaylist.m3u8");*/
            
            
           // ossClient.deleteLiveChannel(bucketName, liveChannel);
        } catch (Exception e) {
            Assert.fail(e.getMessage());
        }
    }
}


其中我们最关注的是 testCreateLiveChannel 类,创建了推流地址,其中参数 LiveChannelStatus.enable 是要让推流变为可用状态。


public void testCreateLiveChannel(String bucketname,OSSClient ossClient) {
        final String liveChannel = "normal-create-live-channel";
        final String liveChannelDesc = "my test live channel";

        try {
            LiveChannelTarget target = new LiveChannelTarget("HLS", 100, 99, "myplaylist.m3u8");
            CreateLiveChannelRequest createLiveChannelRequest = new CreateLiveChannelRequest(
                    bucketName, liveChannel, liveChannelDesc, LiveChannelStatus.Enabled, target);
            
            CreateLiveChannelResult createLiveChannelResult = ossClient.createLiveChannel(createLiveChannelRequest);
            System.out.println(createLiveChannelResult.getPublishUrls());
            /*Assert.assertEquals(createLiveChannelResult.getPublishUrls().size(), 1);
            Assert.assertTrue(createLiveChannelResult.getPublishUrls().get(0).startsWith("rtmp://"));
            Assert.assertTrue(createLiveChannelResult.getPublishUrls().get(0).endsWith("live/" + liveChannel));
            Assert.assertEquals(createLiveChannelResult.getPlayUrls().size(), 1);
            Assert.assertTrue(createLiveChannelResult.getPlayUrls().get(0).startsWith("http://"));
            Assert.assertTrue(createLiveChannelResult.getPlayUrls().get(0).endsWith(liveChannel + "/myplaylist.m3u8"));*/
            
            
           // ossClient.deleteLiveChannel(bucketName, liveChannel);
        } catch (Exception e) {
            Assert.fail(e.getMessage());
        }
    }​


running 主函数,打印出推流地址。
rtmp://hangzhou.oss-cn-hangzhou.aliyuncs.com/live/normal-create-live-channel
请网友们自己亲自搭建环境动手实际测试,有问题可随时留言帖子。

相关实践学习
通义万相文本绘图与人像美化
本解决方案展示了如何利用自研的通义万相AIGC技术在Web服务中实现先进的图像生成。
目录
相关文章
|
2月前
|
机器学习/深度学习 JSON Java
Java调用Python的5种实用方案:从简单到进阶的全场景解析
在机器学习与大数据融合背景下,Java与Python协同开发成为企业常见需求。本文通过真实案例解析5种主流调用方案,涵盖脚本调用到微服务架构,助力开发者根据业务场景选择最优方案,提升开发效率与系统性能。
697 0
|
3月前
|
Cloud Native 前端开发 Java
WebAssembly 与 Java 结合的跨语言协作方案及性能提升策略研究
本文深入探讨了WebAssembly与Java的结合方式,介绍了编译Java为Wasm模块、在Java中运行Wasm、云原生集成等技术方案,并通过金融分析系统的应用实例展示了其高性能、低延迟、跨平台等优势。结合TeaVM、JWebAssembly、GraalVM、Wasmer Java等工具,帮助开发者提升应用性能与开发效率,适用于Web前端、服务器端及边缘计算等场景。
139 0
|
5月前
|
Web App开发 监控 安全
OSS客户端签名直传实践:Web端安全上传TB级文件方案(含STS临时授权)
本文深入解析了客户端直传技术,涵盖架构设计、安全机制、性能优化等方面。通过STS临时凭证与分片上传实现高效安全的文件传输,显著降低服务端负载与上传耗时,提升系统稳定性与用户体验。
570 2
|
5月前
|
存储 Prometheus 监控
OSS监控体系搭建:Prometheus+Grafana实时监控流量、错误码、存储量(开源方案替代云监控自定义视图)
本方案基于Prometheus构建OSS监控系统,涵盖架构设计、指标采集、可视化、告警及性能优化,助力企业实现高可用、低成本的自建监控体系。
580 1
|
2月前
|
缓存 监控 Kubernetes
Java虚拟机内存溢出(Java Heap Space)问题处理方案
综上所述, 解决Java Heap Space溢出需从多角度综合施策; 包括但不限于配置调整、代码审查与优化以及系统设计层面改进; 同样也不能忽视运行期监控与预警设置之重要性; 及早发现潜在风险点并采取相应补救手段至关重要.
498 17
|
2月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
|
4月前
|
缓存 Java 数据库
Java 项目分层架构实操指南及长尾关键词优化方案
本指南详解基于Spring Boot与Spring Cloud的Java微服务分层架构,以用户管理系统为例,涵盖技术选型、核心代码实现、服务治理及部署实践,助力掌握现代化Java企业级开发方案。
218 2
|
4月前
|
JavaScript Java Go
Go、Node.js、Python、PHP、Java五种语言的直播推流RTMP协议技术实施方案和思路-优雅草卓伊凡
Go、Node.js、Python、PHP、Java五种语言的直播推流RTMP协议技术实施方案和思路-优雅草卓伊凡
310 0
|
5月前
|
安全 Java Docker
Docker 部署 Java 应用实战指南与长尾优化方案
本文详细介绍了Docker容器化部署Java应用的最佳实践。首先阐述了采用多阶段构建和精简JRE的镜像优化技术,可将镜像体积减少60%。其次讲解了资源配置、健康检查、启动优化等容器化关键配置,并演示了Spring Boot微服务的多模块构建与Docker Compose编排方案。最后深入探讨了Kubernetes生产部署、监控日志集成、灰度发布策略以及性能调优和安全加固措施,为Java应用的容器化部署提供了完整的解决方案指南。文章还包含大量可落地的代码示例,涵盖从基础到高级的生产环境实践。
274 3
|
5月前
|
存储 运维 分布式计算
OSS迁移实战:从自建MinIO到阿里云OSS的完整数据迁移方案
本文介绍了从自建MinIO迁移至阿里云OSS的完整方案,涵盖成本优化、稳定性提升与生态集成需求。通过双写代理、增量同步、分层校验等技术,解决数据一致性、权限迁移、海量小文件处理等挑战,实现业务零中断与数据强一致性,最终达成79%的TCO降低和显著性能提升。
1372 0