畅直播
  • iOS
  • Android : Java
  • macOS
  • Windows
  • Web
  • Flutter
  • 产品简介
    • 概述
    • 发布日志
    • 基本概念
    • 产品优势
    • 应用场景
    • 限制说明
    • 升级指南
  • 计费说明
  • 下载
  • 快速开始
  • 直播推流
  • 直播拉流
  • 基础功能
  • 进阶功能
  • 最佳实践
  • 常用错误码
  • 服务端 API
  • 客户端 API
  • 常见问题

H.265

更新时间:2022-08-30 17:47

1 功能简介

1.1 功能描述

H.265 是一种高效的视频编码标准,旨在有限带宽下传输更高质量的网络视频。开发者可以在编码或混流时输出 H.265 格式的视频码流。

  • ZEGO Express SDK 从 2.12.0 版本(2021-09-09 发布)开始支持该功能。
  • 如果您需要支持 H.265 视频编码,则需要将线上的 ZEGO Express SDK 都升级到 2.12.0 或以上版本,否则线上版本解码 H.265 可能会出现异常。

H.265 和 H.264 的区别如下:

差异项 H.264 H.265
同等画质下的码率
-
H.265 相比于 H.264 可以节约 30% 码率(实测值)。
软编性能
-
H.265 消耗的算力是 H.264 的 3 倍左右。
软解性能
-
H.265 消耗的算力是 H.264 的 1.5 倍左右。
硬件生态
所有机型基本都支持硬编和硬解。
大部分机型都支持硬编,绝大部分机型都支持硬解。
混流输出
支持。
支持,但价格比 H.264 混流输出更贵,详情可咨询销售。
适用场景
所有场景。
推荐在直播和音视频互动场景使用。

1.2 应用场景

  • 秀场直播、电商直播、互动直播、游戏直播中: 通过 H.265 编码,将码率降低 30% 码率(实测值),分发给万千观众,极大降低 CDN 分发成本。
  • 在视频通话、视频会议、在线教育中: 通过 H.265 编码,在同等码率下,提高画面清晰度,让这些场景通话效果更好。

目前 Web 和小程序平台,不支持连麦和 H.265 拉流。

1.3 概念解释

  • 视频编码:通过特定的压缩技术,将原始视频格式的文件转换成另一种视频格式的方式,便于传输和存储。
  • 混流:是一种把多路音视频流从云端混合成一路流的技术,支持手动混流、自动混流和全自动混流三种方式,详情请参考 混流
  • 转推 CDN:将音视频流从 ZEGO 音视频云推送到 CDN 的过程,详情请参考 通过 CDN 推流/拉流
  • 连麦:是房间内用户之间互动的一种形式,通过 startPublishingStream 接口推自己流的同时,也调用 startPlayingStream 接口拉对方的流,两个用户连麦成功之后即可进行互动通话。

2 服务开通

  1. 使用混流输出 H.265 码流时,需要联系 ZEGO 技术支持开通服务。
  2. 使用混流输出 H.265 码流时,计费有变化,请联系销售了解具体的费用情况。

3 示例源码下载

请参考 下载示例源码 获取源码。

相关源码请查看 “/ZegoExpressExample/Examples/AdvancedStreaming/H265” 目录下的文件。

4 前提条件

在使用 H.265 编解码功能之前,请确保:

5 使用步骤

5.1 检测 H.265 编解码能力

5.1.1 检测 H.265 编码能力

一些老的或低端的移动机型,不支持 H.265 视频编码。此时开发者需要在推流前先通过 isVideoEncoderSupported 接口判断本机是否支持 H.265 视频编码能力。如果支持,才能在推流前通过 setVideoConfig 接口设置 H.265 视频编码类型,否则不生效。

5.1.2 检测 H.265 解码能力

一些老的或低端的移动机型,不支持 H.265 视频解码。在支持拉不同视频码流的场景下,如 CDN 场景,开发者需要在拉流前先通过 isVideoDecoderSupported 接口判断本机是否支持 H.265 视频解码能力。如果支持,才能拉 H.265 视频码流,否则只能拉其他格式的视频码流,例如 H.264。

5.2 连麦混流直播

连麦混流直播包括如下两种实现方式,开发者可以根据实际情况按需接入:

  • 混出不同格式的码流(推荐):混流服务直接输出一路 H.265 混流和一路 H.264 混流,该场景只需要在混流服务进行一次转码,无需 CDN 再转码。相比于混流推 CDN 转码,具有更高的清晰度,费用也更便宜,推荐使用。
  • 混流推 CDN 转码:混流服务直接输出一路 H.265 混流,需要通过 CDN 的转码能力,转出一路 H.265 和一路 H.264 码流。

需要联系 ZEGO 技术支持开通 CDN 转码功能。

5.2.1 混出不同格式的码流(推荐)

该场景下,混流服务通过 ZEGO 实时音视频云接收到主播和连麦嘉宾的推流后,直接输出一路 H.265 混流和一路 H.264 混流,并把两路流都推流到 CDN,观众可以根据自身终端设备是否支持 H.265 视频解码,选择从 CDN 拉 H.265 码流或 H.264 码流。

混出不同格式的码流

主播端

  1. 通过构造函数 ZegoMixerTask 新建一个混流任务对象,然后调用实例方法分别设置输入、输出等参数。
  2. 通过混流任务对象 ZegoMixerTask 中的 setInputList 属性设置混流任务输入流列表(混流输入中流的编码格式支持 H.264 和 H.265 ),默认最多支持输入 9 路流,请自行处理流布局。
  3. 通过混流任务对象 ZegoMixerTask 中的 setOutputList 属性设置混流任务输出流列表。假设当前场景下,混流服务直接转码出一路 H.264 混流和一路 H.265混流,即混流输出视频编码格式为 H.264 和 H.265。
  4. 调用 startMixerTask 接口发起混流任务。
  5. 开发者通知 App 的业务服务端流已新增。
// 调用 startMixerTask 发起混流
String taskID = ""; // 请输入 taskID
ZegoMixerTask task = new ZegoMixerTask(taskID);

// 请自行设置 videoConfig
ZegoMixerVideoConfig videoConfig = new ZegoMixerVideoConfig(720, 1280, 15, 1500);
task.setVideoConfig(videoConfig);

task.setAudioConfig(new ZegoMixerAudioConfig());

// 注意,混流输入中流的编码格式支持 H.264 和 H.265, 请自行处理流布局及输入
ArrayList<ZegoMixerInput> inputList = new ArrayList<>();
task.setInputList(inputList);

// 混流两路输出
// 注意: 输出 target 可以是 streamID 或 CDN 地址,二者在观众端处理方式不同,该场景推荐直接传入 stremaID
// 注意: ZegoMixerOutput 中的码率优先级高于 ZegoMixerVideoConfig 中的码率
String h264StreamID = ""; // 请输入 h264StreamID
String h265StreamID = ""; // 请输入 h265StreamID
int h264Bitrate = 2244; // 请输入 h264 码率,此码率为当前分辨率帧率(720p, 15fps)的推荐码率。
int h265Bitrate = 1795; // 请输入 h265 码率,此码率为当前分辨率帧率(720p, 15fps)的推荐码率。
ArrayList<ZegoMixerOutput> outputList = new ArrayList<>();

ZegoMixerOutput outputH264 = new ZegoMixerOutput(h264StreamID);
ZegoMixerOutputVideoConfig outputH264VideoConfig = new ZegoMixerOutputVideoConfig(ZegoVideoCodecID.getZegoVideoCodecID(0), h264Bitrate);
outputH264.setVideoConfig(outputH264VideoConfig);
outputList.add(outputH264);
ZegoMixerOutput outputH265 = new ZegoMixerOutput(h265StreamID);
ZegoMixerOutputVideoConfig outputH265VideoConfig = new ZegoMixerOutputVideoConfig(ZegoVideoCodecID.getZegoVideoCodecID(3), h265Bitrate);
outputH265.setVideoConfig(outputH265VideoConfig);
outputList.add(outputH265);
task.setOutputList(outputList);

// 开始混流
engine.startMixerTask(task, new IZegoMixerStartCallback() {

    @Override
    public void onMixerStartResult(int errorCode, JSONObject var2) {
        // 混流任务回调
    }
});
// 开发者通知 App 的业务服务端流已新增

观众端

  1. 观众端从 App 的业务服务端收到流新增通知。
  2. 调用 isVideoDecoderSupported 接口查询观众端自身设备是否支持 H.265 解码格式。
// 从 App 的业务服务端收到流新增通知

boolean h265DecoderSupport = engine.isVideoDecoderSupported(ZegoVideoCodecID.getZegoVideoCodecID(3));

String h264StreamID = ""; // h264StreamID
String h265StreamID = ""; // h265StreamID
View view = playView; // 拉流需要渲染的 view
ZegoCanvas playCanvas = new ZegoCanvas(view);

if (h265DecoderSupport) {
    // 支持 H.265 解码
    engine.startPlayingStream(h265StreamID, playCanvas);
}
else {
    // 不支持 H.265 解码
    engine.startPlayingStream(h264StreamID, playCanvas);
}

5.2.2 混流后推 CDN 再转码

该场景下,混流服务通过 ZEGO 实时音视频云接收到主播和连麦嘉宾的推流后,直接输出一路 H.265 混流,并把这路混流推流到 CDN,通过 CDN 的转码能力,观众可以根据自身终端设备是否支持 H.265 视频解码,选择从 CDN 拉 H.265 码流或 H.264 码流。

混流推CDN 转码

主播端

  1. 通过构造函数 ZegoMixerTask 新建一个混流任务对象,然后调用实例方法分别设置输入、输出等参数。
  2. 通过混流任务对象 ZegoMixerTask 中的 setInputList 属性设置混流任务输入流列表(混流输入中流的编码格式支持 H.264 和 H.265 ),默认最多支持输入 9 路流,请自行处理流布局。
  3. 通过混流任务对象 ZegoMixerTask 中的 setOutputList 属性设置混流任务输出流列表。假设当前场景下,混流服务直接输出一路 H.265 混流,即混流输出视频编码格式为H.265。
  4. 调用 startMixerTask 接口发起混流任务。
  5. 开发者通知 App 的业务服务端流已新增。
// 调用 startMixerTask 发起混流
String taskID = ""; // 请输入 taskID
ZegoMixerTask task = new ZegoMixerTask(taskID);

// 请自行设置 videoConfig
ZegoMixerVideoConfig videoConfig = new ZegoMixerVideoConfig(720, 1280, 15, 1500);
task.setVideoConfig(videoConfig);

task.setAudioConfig(new ZegoMixerAudioConfig());

// 注意,混流输入中流的编码格式支持 H.264 和 H.265, 请自行处理流布局及输入
ArrayList<ZegoMixerInput> inputList = new ArrayList<>();
task.setInputList(inputList);

String publishCdnUrl = ""; // 请输入 CDN URL
int h265Bitrate = 1795; // 请输入 h265 码率,此码率为当前分辨率帧率(720p, 15fps)的推荐码率。
// 注意,由于这里需要使用 CDN 转码, target 需要传入 CDN URL
ArrayList<ZegoMixerOutput> outputList = new ArrayList<>();

ZegoMixerOutput outputH265 = new ZegoMixerOutput(publishCdnUrl);
ZegoMixerOutputVideoConfig outputH265VideoConfig = new ZegoMixerOutputVideoConfig(ZegoVideoCodecID.getZegoVideoCodecID(3), h265Bitrate);
outputH265.setVideoConfig(outputH265VideoConfig);
outputList.add(outputH265);
task.setOutputList(outputList);

// 开始混流
engine.startMixerTask(task, new IZegoMixerStartCallback() {

    @Override
    public void onMixerStartResult(int errorCode, JSONObject var2) {
        // 混流任务回调
    }
});

// 开发者通知 App 的业务服务端流已新增

观众端

  1. 观众端从 App 的业务服务端收到流新增通知。
  2. 调用 isVideoDecoderSupported 接口查询观众端自身设备是否支持 H.265 解码格式。
// 从 App 的业务服务端收到流新增通知

boolean h265DecoderSupport = engine.isVideoDecoderSupported(ZegoVideoCodecID.getZegoVideoCodecID(3));

String playStreamID = "";
View view = playView; // 拉流需要渲染的 view
ZegoCanvas playCanvas = new ZegoCanvas(view);

if (h265DecoderSupport) {
    // 支持 H.265 解码
    String h265Url = ""; // 请填入 H.265 Url 地址

    // 注意: ZegoCDNConfig 和 ZegoPlayerConfig 中有其他的可配置项
    ZegoCDNConfig cdnConfig = new ZegoCDNConfig();
    // H.265 CDN 拉流地址
    cdnConfig.url = h265Url;
    ZegoPlayerConfig playerConfig = new ZegoPlayerConfig();
    playerConfig.cdnConfig = cdnConfig;
    engine.startPlayingStream(playStreamID, playCanvas, playerConfig);
}
else {
    // 不支持 H.265 解码
    String h264Url = ""; // 请填入 H.264 Url 地址

    // 注意: ZegoCDNConfig 和 ZegoPlayerConfig 中有其他的可配置项
    ZegoCDNConfig cdnConfig = new ZegoCDNConfig();
    // H.264 CDN 拉流地址
    cdnConfig.url = h264Url;
    ZegoPlayerConfig playerConfig = new ZegoPlayerConfig();
    playerConfig.cdnConfig = cdnConfig;
    engine.startPlayingStream(playStreamID, playCanvas, playerConfig);
}

5.3 单主播直播

5.3.1 实时网络转推 CDN 直播

该场景具有以下两个特点:

  • 主播通过 ZEGO 实时音视频云转推到 CDN,通过 CDN 的转码能力,观众可以根据自身终端设备是否支持 H.265 视频解码,选择从 CDN 拉 H.265 码流或 H.264 码流。
  • 主播推 H.265 码流时,连麦嘉宾从 ZEGO 实时音视频云直接拉流进行实时互动,此时要求连麦嘉宾的终端设备支持 H.265 视频解码能力。

转推CDN 直播

主播端

  1. 创建引擎后,调用 enableHardwareEncoder 接口开启硬件编码(若推流后更改配置,需要等下一次推流才生效),开启后会使用 GPU 进行编码,降低 CPU 使用率。
  2. 调用 isVideoEncoderSupported 接口查询主播端设备是否支持指定视频编码类型。
  1. 推流前调用 setVideoConfig 接口,通过 codecID 设置视频编码格式(若推流后更改配置,需要等下一次推流才生效)。如果设置了 H.265 编码,则:
    1. 可以调用 enableH265EncodeFallback 接口开启 H.265 编码失败后自动降级到 H.264 编码(默认开启)。开启后,当不支持 H.265 编码或 H.265 编码失败时,SDK 内部会尝试降级使用 H.264 编码进行推流。关闭后,当不支持 H.265 编码或 H.265 编码失败时,直接推流失败。
    2. 调用 addPublishCdnUrl 接口添加 ZEGO 实时音视频云的音视频流转推至 CDN 的 URL 地址。
    3. 调用 startPublishingStream 接口开始推流,当推流成功后,同房间内其他用户可通过监听 onRoomStreamUpdate 回调来获取流的新增情况。
    4. 开发者通知 App 的业务服务端该条推流的编码格式,以便通知拉流端根据不同的推流编码格式做相应的处理。
// 移动端使用 H.265 编码需要开启硬件编码
engine.enableHardwareEncoder(true);

// 查询是否支持 H.265 编码
boolean h265EncoderSupport = engine.isVideoEncoderSupported(ZegoVideoCodecID.getZegoVideoCodecID(3));

ZegoVideoConfig videoConfig = new ZegoVideoConfig();
if (h265EncoderSupport) {
    // 支持 H.265 编码
    videoConfig.codecID = ZegoVideoCodecID.getZegoVideoCodecID(3);
} else {
    // 不支持 H.265 编码
    videoConfig.codecID = ZegoVideoCodecID.getZegoVideoCodecID(0);
}
engine.setVideoConfig(videoConfig);

if (h265EncoderSupport) {
    // 通过 enableH265EncodeFallback 选择是否开启 H.265 编码失败自动降级能力。
    engine.enableH265EncodeFallback(true);
}

String publishStreamID = ""; // 请输入 streamID
String publishCdnUrl = ""; // 请输入 CdnUrl

// 添加 CDN 转推地址
engine.addPublishCdnUrl(publishCdnUrl, publishStreamID, new IZegoPublisherUpdateCdnUrlCallback() {
    @Override
    public void onPublisherUpdateCdnUrlResult(int i) {
        // 判断转推 CDN 地址是否添加成功
    }
});
engine.startPublishingStream(publishStreamID);

// 开发者通知 App 的业务服务端该条推流的编码格式,以便通知拉流端根据不同的推流编码格式做相应的处理

观众端

  1. 主播推流后,观众端通过 onRoomStreamUpdate 接口收到流新增通知。
  2. 观众端从 App 的业务服务端获取该条推流的编码格式。
  • 如果是 H.264 格式,观众可以调用 startPlayingStream 接口从 CDN 直接拉主播端的流。
  • 如果是 H.265 格式,需要先调用 isVideoDecoderSupported 接口查询观众端自身设备是否支持 H.265 解码格式。
//收到流新增通知 onRoomStreamUpdate
@Override
public void onRoomStreamUpdate(String roomID, ZegoUpdateType updateType, ArrayList<ZegoStream> streamList, JSONObject extendedData) {
    super.onRoomStreamUpdate(roomID, updateType, streamList, extendedData);

    int videoCodecID = 0; // 从 App 的业务服务端获取该条流的编码格式。
    String playStreamID = ""; // 请输入 streamID
    View view = playView; // 拉流需要渲染的 view
    ZegoCanvas playCanvas = new ZegoCanvas(view);

    if (videoCodecID == ZegoVideoCodecID.getZegoVideoCodecID(3).value()) {
        // 编码格式为 H.265
        boolean h265DecoderSupport = engine.isVideoDecoderSupported(ZegoVideoCodecID.getZegoVideoCodecID(3));

        // 不支持解码则不拉流
        if (h265DecoderSupport) {
            // 支持 H.265 解码
            String h265Url = ""; // 请填入 H.265 Url 地址

            // 注意: ZegoCDNConfig 和 ZegoPlayerConfig 中有其他的可配置项
            ZegoCDNConfig cdnConfig = new ZegoCDNConfig();
            // H.265 CDN 拉流地址
            cdnConfig.url = h265Url;
            ZegoPlayerConfig playerConfig = new ZegoPlayerConfig();
            playerConfig.cdnConfig = cdnConfig;
            engine.startPlayingStream(playStreamID, playCanvas, playerConfig);
        } else {
            // 不支持 H.265 解码
            String h264Url = ""; // 请填入 H.264 Url 地址

            // 注意: ZegoCDNConfig 和 ZegoPlayerConfig 中有其他的可配置项
            ZegoCDNConfig cdnConfig = new ZegoCDNConfig();
            // H.264 CDN 拉流地址
            cdnConfig.url = h264Url;
            ZegoPlayerConfig playerConfig = new ZegoPlayerConfig();
            playerConfig.cdnConfig = cdnConfig;
            engine.startPlayingStream(playStreamID, playCanvas, playerConfig);
        }
    }
    else if (videoCodecID == ZegoVideoCodecID.getZegoVideoCodecID(0).value()) {
        // 编码格式为 H.264
        engine.startPlayingStream(playStreamID, playCanvas);
    }
}

连麦嘉宾端

  1. 主播推流后,连麦嘉宾通过 onRoomStreamUpdate 接口收到流的新增通知。
  2. 连麦嘉宾从 App 的业务服务端获取该条推流的编码格式。
  • 如果是 H.264 格式,连麦嘉宾可以调用 startPlayingStream 接口从 ZEGO 实时音视频云直接拉主播端的流。
  • 如果是 H.265 格式,需要先调用 isVideoDecoderSupported 接口查询自身设备是否支持 H.265 解码格式。
    • 若支持,则调用 startPlayingStream 接口从 ZEGO 实时音视频云 拉 H.265 码流。
    • 若不支持,则提示本终端设备不支持拉该流。
//收到流新增通知 onRoomStreamUpdate
@Override
public void onRoomStreamUpdate(String roomID, ZegoUpdateType updateType, ArrayList<ZegoStream> streamList, JSONObject extendedData) {
    super.onRoomStreamUpdate(roomID, updateType, streamList, extendedData);

    int videoCodecID = 0; // 从 App 的业务服务端获取该条流的编码格式。
    String playStreamID = ""; // 请输入 streamID
    View view = playView; // 拉流需要渲染的 view
    ZegoCanvas playCanvas = new ZegoCanvas(view);
    ZegoPlayerConfig config = new ZegoPlayerConfig();
    config.resourceMode = ZegoStreamResourceMode.ONLY_RTC; // 仅从 RTC 拉流

    if (videoCodecID == ZegoVideoCodecID.getZegoVideoCodecID(3).value()) {
        // 编码格式为 H.265
        boolean h265DecoderSupport = engine.isVideoDecoderSupported(ZegoVideoCodecID.getZegoVideoCodecID(3));

        // 不支持解码则不拉流
        if (h265DecoderSupport) {
            // 支持 H.265 解码
            engine.startPlayingStream(playStreamID, playCanvas, config);
        }
    }
    else if (videoCodecID == ZegoVideoCodecID.getZegoVideoCodecID(0).value()) {
        // 编码格式为 H.264
        engine.startPlayingStream(playStreamID, playCanvas, config);
    }
}

5.4 录制

如果进行本地服务端录制、云端录制、数据流录制时使用了 H.265 编解码功能,则会影响录制文件的生成,详情如下:

在对推流(H.265 视频编码码流)进行录制时,有可能因为 H.265 编码失败而触发编码降级,此时会收到 onPublisherVideoEncoderChanged 回调,表示视频编码格式发生变更。

该场景下,为了避免对录制文件造成损坏,SDK 内部会结束并保存当前的录制任务,并自动重启一个新的录制任务。新录制任务的录制文件路径会重新生成,避免覆盖原始录制文件。新文件的生成规则为给原始的录制文件名基础上加一个时间戳:

例如,开发者传入的原始录制文件路径为:/user/data/mediarecord.mp4,则新的录制文件为: /user/data/mediarecord_1626880634948.mp4,其中 1626880634948 为当前时间戳。

如果开发者在录制期间收到过 onPublisherVideoEncoderChanged 回调,需要在录制结束后,收集录制文件存储路径下的其他文件。

6 API 参考列表

方法 描述
createEngine 创建引擎
enableHardwareEncoder 开/关硬件编码
startPublishingStream 开始推流
startPlayingStream 开始拉流
setVideoConfig 设置视频配置
onRoomStreamUpdate 相同房间内其他用户推的流增加或减少的通知
isVideoEncoderSupported 是否支持指定视频编码类型
isVideoDecoderSupported 是否支持指定视频解码格式
enableH265EncodeFallback 是否开启 H.265 编码自动降级到 H.264 编码
onPublisherVideoEncoderChanged 视频编码器变更回调
startMixerTask 开始混流任务

7 常见问题

  1. H.265 在硬编出现错误怎么办?

可以调用 enableH265EncodeFallback 接口开启降级功能(默认开启),若 H.265 硬编失败则降级成 H.264,若同时在使用录制功能,则录制文件变为两份。

  1. H.265 是否会自动从硬解降到软解?

会的,若解码时发现硬解失败,会自动降级成软解。

  1. H.265 如何收费?

客户端开启 H.265 功能不需要收费,但是混流输出 H.265 需要收取混流费用,比混流输出 H.264 价格更贵,详情可咨询销售。

  1. 混流输入 H.265 流,输出 H.264 流时,计费是否有变化?

没有变化,按输出 H.264 计费。

  1. H.265 解码对于硬件的要求是什么?

目前市场上所有机型都支持 H.265 解码,经测试大概在 2013 年之前的低端机型解码可能会有帧率波动。