H.265
Feature Introduction
Feature Description
H.265 is an efficient video coding standard designed to transmit higher quality network video over limited bandwidth. Developers can output H.265 format video streams when encoding or mixing streams.
- ZEGO Express SDK has supported this feature since version 2.12.0 (released on 2021-09-09).
- If you need to support H.265 video encoding, you need to upgrade all online ZEGO Express SDKs to version 2.12.0 or above, otherwise decoding H.265 on online versions may cause abnormalities.
The differences between H.265 and H.264 are as follows:
| Difference Item | H.264 | H.265 |
|---|---|---|
| Bitrate at same picture quality | - | H.265 can save 30% bitrate compared to H.264 (measured value). |
| Software encoding performance | - | H.265 consumes about 3 times the computing power of H.264. |
| Software decoding performance | - | H.265 consumes about 1.5 times the computing power of H.264. |
| Hardware ecosystem | Basically all models support hardware encoding and decoding. | Most models support hardware encoding, and the vast majority of models support hardware decoding. |
| Stream mixing output | Supported. | Supported, but the price is more expensive than H.264 stream mixing output, please consult sales for details. |
| Applicable scenarios | All scenarios. | Recommended for use in live streaming and audio/video interaction scenarios. |
Application Scenarios
- In show live streaming, e-commerce live streaming, interactive live streaming, game live streaming: Through H.265 encoding, the bitrate is reduced by 30% (measured value), distributed to thousands of viewers, greatly reducing CDN distribution costs.
- In video calls, video conferences, online education: Through H.265 encoding, at the same bitrate, improve picture clarity, making these scenarios call effects better.
Currently, Web and mini-program platforms do not support co-hosting and H.265 stream playing.
Concept Explanation
- Video encoding: A method of converting original video format files into another video format through specific compression technology for easy transmission and storage.
- Stream mixing: A technology that mixes multiple audio/video streams into one stream from the cloud, supporting three methods: manual stream mixing, automatic stream mixing, and fully automatic stream mixing. For details, please refer to Stream Mixing.
- Relay to CDN: The process of pushing audio/video streams from ZEGO audio/video cloud to CDN. For details, please refer to Pushing/Playing Streams via CDN.
- Co-hosting: A form of interaction between users in a room. While pushing their own stream through the startPublishingStream interface, they also call the startPlayingStream interface to play each other's stream. After two users successfully co-host, they can conduct interactive calls.
Example Source Code Download
Please refer to Download Example Source Code to get the source code.
For related source code, please view files in the "lib\topics\StreamAdvanced\h265" directory.
Service Activation
- When using stream mixing to output H.265 streams, you need to contact ZEGO technical support to activate the service.
- When using stream mixing to output H.265 streams, there are changes in billing. Please contact ZEGO sales personnel for specific pricing information.
Prerequisites
Before using the H.265 codec feature, please ensure:
- A project has been created in the ZEGO Console, and a valid AppID and AppSign have been applied for. For details, please refer to Console - Project Information.
- ZEGO Express SDK has been integrated in the project, and basic audio/video publishing and playing functions have been implemented. For details, please refer to Quick Start - Integration and Quick Start - Implementation Flow.
Implementation Method
Detect H.265 Codec Capability
Detect H.265 Encoding Capability
Some older or low-end mobile models do not support H.265 video encoding. At this time, developers need to use the isVideoEncoderSupported interface to check whether the local device supports H.265 video encoding capability before publishing stream. If supported, the H.265 video encoding type can be set through the setVideoConfig interface before publishing stream, otherwise it will not take effect.
Detect H.265 Decoding Capability
Some older or low-end mobile models do not support H.265 video decoding. In scenarios that support pulling different video streams, such as CDN scenarios, developers need to use the isVideoDecoderSupported interface to check whether the local device supports H.265 video decoding capability before playing stream. If supported, H.265 video streams can be played, otherwise only other format video streams, such as H.264, can be played.
Co-hosting Stream Mixing Live Streaming
Co-hosting stream mixing live streaming includes the following two implementation methods. Developers can choose according to their actual needs:
- Mixing streams of different formats (recommended): The stream mixing service directly outputs one H.265 mixed stream and one H.264 mixed stream. This scenario only requires one transcoding by the stream mixing service, without the need for CDN transcoding. Compared with stream mixing pushing to CDN transcoding, it has higher clarity and is cheaper, so it is recommended to use.
- Stream mixing push to CDN transcoding: The stream mixing service directly outputs one H.265 mixed stream, which needs to be transcoded by CDN's transcoding capability to output one H.265 and one H.264 stream.
You need to contact ZEGO technical support to activate the CDN transcoding feature.
Mixing Streams of Different Formats (Recommended)
In this scenario, after the stream mixing service receives the streams from the host and co-hosting guests through ZEGO real-time audio/video cloud, it directly outputs one H.265 mixed stream and one H.264 mixed stream, and pushes both streams to CDN. The audience can choose to pull H.265 stream or H.264 stream from CDN based on whether their terminal device supports H.265 video decoding.

Host Side
- Create a new stream mixing task object through the constructor ZegoMixerTask, then call instance methods to set input, output and other parameters separately.
- Set the stream mixing task input stream list through the inputList attribute in the stream mixing task object ZegoMixerTask (the encoding format of streams in stream mixing input supports H.264 and H.265, up to 9 streams by default, please handle the stream layout yourself).
- Set the stream mixing task output stream list through the outputList attribute in the stream mixing task object ZegoMixerTask. Assume that in the current scenario, the stream mixing service directly transcodes one H.264 mixed stream and one H.265 mixed stream, that is, the stream mixing output video encoding format is H.264 and H.265.
- Call the startMixerTask interface to initiate a stream mixing task.
- The developer notifies the App's business server that the stream has been added.
// Call startMixerTask to initiate stream mixing
String taskID = ""; // Please enter taskID
var task = ZegoMixerTask(taskID);
// Please set videoConfig yourself
var videoConfig = ZegoMixerVideoConfig(720, 1280, 15, 1500);
task.videoConfig = videoConfig;
task.audioConfig = ZegoMixerAudioConfig.defaultConfig();
// Note, the encoding format of streams in stream mixing input supports H.264 and H.265, please handle stream layout and input yourself
List<ZegoMixerInput> inputList = [];
task.inputList = inputList;
// Mix two streams output
// Note: The output target can be streamID or CDN address, they are handled differently at the audience end, this scenario recommends directly passing streamID
// Note: The bitrate priority in ZegoMixerOutput is higher than the bitrate in ZegoMixerVideoConfig
String h264StreamID = ""; // Please enter h264StreamID
String h265StreamID = ""; // Please enter h265StreamID
int h264Bitrate = 2244; // Please enter h264 bitrate, this bitrate is the recommended bitrate for the current resolution and frame rate (720p, 15fps)
int h265Bitrate = 1795; // Please enter h265 bitrate, this bitrate is the recommended bitrate for the current resolution and frame rate (720p, 15fps)
List<ZegoMixerOutput> outputList = [];
var outputH264 = ZegoMixerOutput(h264StreamID);
var outputH264VideoConfig = ZegoMixerOutputVideoConfig(ZegoVideoCodecID.Default, h264Bitrate);
outputH264.videoConfig = outputH264VideoConfig;
outputList.add(outputH264);
var outputH265 = ZegoMixerOutput(h265StreamID);
var outputH265VideoConfig = ZegoMixerOutputVideoConfig(ZegoVideoCodecID.H265, h265Bitrate);
outputH265.videoConfig = outputH265VideoConfig;
outputList.add(outputH265);
task.outputList = outputList;
// Start stream mixing
ZegoExpressEngine.instance.startMixerTask(task).then((ZegoMixerStartResult result) {
// Stream mixing task callback
});
// Developer notifies App's business server that the stream has been addedAudience Side
- The audience side receives a stream addition notification from the App's business server.
- Call the isVideoDecoderSupported interface to check whether the audience's device supports H.265 decoding format.
- If supported, call the startPlayingStream interface to pull H.265 stream from CDN.
- If not supported, call the startPlayingStream interface to pull H.264 stream from CDN.
// Receive stream addition notification from App's business server
bool h265DecoderSupport = await ZegoExpressEngine.instance.isVideoDecoderSupported(ZegoVideoCodecID.H265);
String h264StreamID = ""; // h264StreamID
String h265StreamID = ""; // h265StreamID
int viewID = playViewID; // viewID needed for playing stream rendering, obtained through sdk's createCanvasView
var playCanvas = ZegoCanvas(viewID);
if (h265DecoderSupport) {
// Supports H.265 decoding
ZegoExpressEngine.instance.startPlayingStream(h265StreamID, canvas: playCanvas);
}
else {
// Does not support H.265 decoding
ZegoExpressEngine.instance.startPlayingStream(h264StreamID, canvas: playCanvas);
}Stream Mixing Push to CDN Transcoding
In this scenario, after the stream mixing service receives the streams from the host and co-hosting guests through ZEGO real-time audio/video cloud, it directly outputs one H.265 mixed stream, and pushes this stream to CDN. Through CDN's transcoding capability, the audience can choose to pull H.265 stream or H.264 stream from CDN based on whether their terminal device supports H.265 video decoding.

Host Side
- Create a new stream mixing task object through the constructor ZegoMixerTask, then call instance methods to set input, output and other parameters separately.
- Set the stream mixing task input stream list through the inputList attribute in the stream mixing task object ZegoMixerTask (the encoding format of streams in stream mixing input supports H.264 and H.265, up to 9 streams by default, please handle the stream layout yourself).
- Set the stream mixing task output stream list through the outputList attribute in the stream mixing task object ZegoMixerTask. Assume that in the current scenario, the stream mixing service directly outputs one H.265 mixed stream, that is, the stream mixing output video encoding format is H.265.
- Call the startMixerTask interface to initiate a stream mixing task.
- The developer notifies the App's business server that the stream has been added.
// Call startMixerTask to initiate stream mixing
String taskID = ""; // Please enter taskID
var task = ZegoMixerTask(taskID);
// Please set videoConfig yourself
var videoConfig = ZegoMixerVideoConfig(720, 1280, 15, 1500);
task.videoConfig = videoConfig;
task.audioConfig = ZegoMixerAudioConfig.defaultConfig();
// Note, the encoding format of streams in stream mixing input supports H.264 and H.265, please handle stream layout and input yourself
List<ZegoMixerInput> inputList = [];
task.inputList = inputList;
String publishCdnUrl = ""; // Please enter CDN URL
int h265Bitrate = 1795; // Please enter h265 bitrate, this bitrate is the recommended bitrate for the current resolution and frame rate (720p, 15fps)
// Note, since CDN transcoding is needed here, target needs to be passed in as CDN URL
List<ZegoMixerOutput> outputList = [];
var outputH265 = ZegoMixerOutput(publishCdnUrl);
var outputH265VideoConfig = ZegoMixerOutputVideoConfig(ZegoVideoCodecID.H265, h265Bitrate);
outputH265.videoConfig = outputH265VideoConfig;
outputList.add(outputH265);
task.outputList = outputList;
// Start stream mixing
ZegoExpressEngine.instance.startMixerTask(task).then((ZegoMixerStartResult result) {
// Stream mixing task callback
});
// Developer notifies App's business server that the stream has been addedAudience Side
- The audience side receives a stream addition notification from the App's business server.
- Call the isVideoDecoderSupported interface to check whether the audience's device supports H.265 decoding format.
- If supported, call the startPlayingStream interface to pull H.265 stream from CDN.
- If not supported, call the startPlayingStream interface to pull H.264 stream from CDN.
// Receive stream addition notification from App's business server
bool h265DecoderSupport = await ZegoExpressEngine.instance.isVideoDecoderSupported(ZegoVideoCodecID.H265);
String playStreamID = "";
int viewID = playViewID; // viewID needed for playing stream rendering, obtained through sdk's createCanvasView
var playCanvas = ZegoCanvas(view);
if (h265DecoderSupport) {
// Supports H.265 decoding
String h265Url = ""; // Please enter H.265 URL address
// H.265 CDN playing address
String url = h265Url;
// Note: ZegoCDNConfig and ZegoPlayerConfig have other configurable items
var cdnConfig = ZegoCDNConfig(url, "");
var playerConfig = ZegoPlayerConfig.defaultConfig();
playerConfig.cdnConfig = cdnConfig;
ZegoExpressEngine.instance.startPlayingStream(playStreamID, canvas: playCanvas, config: playerConfig);
}
else {
// Does not support H.265 decoding
String h264Url = ""; // Please enter H.264 URL address
// H.264 CDN playing address
String url = h264Url;
// Note: ZegoCDNConfig and ZegoPlayerConfig have other configurable items
var cdnConfig = ZegoCDNConfig(url, "");
var playerConfig = ZegoPlayerConfig.defaultConfig();
playerConfig.cdnConfig = cdnConfig;
ZegoExpressEngine.instance.startPlayingStream(playStreamID, canvas: playCanvas, config: playerConfig);
}Single Host Live Streaming
Real-time Network Relay to CDN Live Streaming
This scenario has the following two characteristics:
- The host relays to CDN through ZEGO real-time audio/video cloud. Through CDN's transcoding capability, the audience can choose to pull H.265 stream or H.264 stream from CDN based on whether their terminal device supports H.265 video decoding.
- When the host pushes H.265 stream, co-hosting guests pull streams directly from ZEGO real-time audio/video cloud for real-time interaction. At this time, co-hosting guests' terminal devices are required to support H.265 video decoding capability.

Host Side
After creating the engine, call the enableHardwareEncoder interface to enable hardware encoding (if the configuration is changed after pushing stream, you need to wait for the next push stream to take effect). After enabling, GPU will be used for encoding, reducing CPU usage.
Call the isVideoEncoderSupported interface to check whether the host device supports the specified video encoding type.
Before pushing stream, call the setVideoConfig interface to set the video encoding format through codecID (if the configuration is changed after pushing stream, you need to wait for the next push stream to take effect). If H.265 encoding is set, then:
You can call the enableH265EncodeFallback interface to enable automatic fallback from H.265 encoding to H.264 encoding when H.265 encoding fails (enabled by default). After enabling, when H.265 encoding is not supported or H.265 encoding fails, the SDK will internally attempt to fallback to using H.264 encoding for pushing stream. After disabling, when H.265 encoding is not supported or H.265 encoding fails, pushing stream will fail directly.
Call the addPublishCdnUrl interface to add the URL address for relaying audio/video streams from ZEGO real-time audio/video cloud to CDN.
Call the startPublishingStream interface to start pushing stream. After successful pushing, other users in the same room can get the stream addition situation by listening to the onRoomStreamUpdate callback.
The developer notifies the App's business server of the encoding format of this push stream, so that the playing end can handle accordingly based on different push encoding formats.
// Mobile devices need to enable hardware encoding to use H.265 encoding
ZegoExpressEngine.instance.enableHardwareEncoder(true);
// Check if H.265 encoding is supported
bool h265EncoderSupport = await ZegoExpressEngine.instance.isVideoEncoderSupported(ZegoVideoCodecID.H265);
var videoConfig = new ZegoVideoConfig.preset(ZegoVideoConfigPreset.Preset720P);
if (h265EncoderSupport) {
// Supports H.265 encoding
videoConfig.codecID = ZegoVideoCodecID.H265;
} else {
// Does not support H.265 encoding
videoConfig.codecID = ZegoVideoCodecID.Default;
}
ZegoExpressEngine.instance.setVideoConfig(videoConfig);
if (h265EncoderSupport) {
// Choose whether to enable H.265 encoding failure automatic fallback capability through enableH265EncodeFallback
ZegoExpressEngine.instance.enableH265EncodeFallback(true);
}
String publishStreamID = ""; // Please enter streamID
String publishCdnUrl = ""; // Please enter CdnUrl
// Add CDN relay address
ZegoExpressEngine.instance.addPublishCdnUrl(publishStreamID, publishCdnUrl).then((ZegoPublisherUpdateCdnUrlResult result) {
// Determine whether the relay CDN address was added successfully
});
ZegoExpressEngine.instance.startPublishingStream(publishStreamID);
// Developer notifies App's business server of the encoding format of this push stream, so that the playing end can handle accordingly based on different push encoding formatsAudience Side
- After the host pushes stream, the audience side receives a stream addition notification through the onRoomStreamUpdate interface.
- The audience side gets the encoding format of this push stream from the App's business server.
- If it is H.264 format, the audience can call the startPlayingStream interface to pull the host's stream directly from CDN.
- If it is H.265 format, you need to first call the isVideoDecoderSupported interface to check whether the audience's device supports H.265 decoding format.
- If supported, call the startPlayingStream interface to pull H.265 stream from CDN.
- If not supported, call the startPlayingStream interface to pull H.264 stream from CDN.
// Receive stream addition notification onRoomStreamUpdate
ZegoExpressEngine.onRoomStreamUpdate = (String roomID, ZegoUpdateType updateType, List<ZegoStream> streamList, Map<String, dynamic> extendedData) {
ZegoVideoCodecID videoCodecID = ZegoVideoCodecID.Default; // Get the encoding format of this stream from the App's business server.
String playStreamID = ""; // Please enter streamID
int viewID = playViewID; // viewID needed for playing stream rendering, obtained through sdk's createCanvasView
var playCanvas = ZegoCanvas(viewID);
if (videoCodecID == ZegoVideoCodecID.H265) {
// Encoding format is H.265
bool h265DecoderSupport = await ZegoExpressEngine.instance.isVideoDecoderSupported(ZegoVideoCodecID.H265);
// If decoding is not supported, do not pull stream
if (h265DecoderSupport) {
// Supports H.265 decoding
String h265Url = ""; // Please enter H.265 URL address
// H.265 CDN playing address
String url = h265Url;
// Note: ZegoCDNConfig and ZegoPlayerConfig have other configurable items
var cdnConfig = ZegoCDNConfig(url, "");
var playerConfig = new ZegoPlayerConfig.defaultConfig();
playerConfig.cdnConfig = cdnConfig;
ZegoExpressEngine.instance.startPlayingStream(playStreamID, canvas: playCanvas, config: playerConfig);
} else {
// Does not support H.265 decoding
String h264Url = ""; // Please enter H.264 URL address
// H.264 CDN playing address
String url = h264Url;
// Note: ZegoCDNConfig and ZegoPlayerConfig have other configurable items
var cdnConfig = new ZegoCDNConfig(url, "");
var playerConfig = ZegoPlayerConfig.defaultConfig();
playerConfig.cdnConfig = cdnConfig;
ZegoExpressEngine.instance.startPlayingStream(playStreamID, canvas: playCanvas, config: playerConfig);
}
}
else if (videoCodecID == ZegoVideoCodecID.Default) {
// Encoding format is H.264
ZegoExpressEngine.instance.startPlayingStream(playStreamID, canvas: playCanvas);
}
};Co-hosting Guest Side
- After the host pushes stream, co-hosting guests receive stream addition notifications through the onRoomStreamUpdate interface.
- Co-hosting guests get the encoding format of this push stream from the App's business server.
- If it is H.264 format, co-hosting guests can call the startPlayingStream interface to pull the host's stream directly from ZEGO real-time audio/video cloud.
- If it is H.265 format, you need to first call the isVideoDecoderSupported interface to check whether their device supports H.265 decoding format.
- If supported, call the startPlayingStream interface to pull H.265 stream from ZEGO real-time audio/video cloud.
- If not supported, prompt that the current device does not support pulling this stream.
// Receive stream addition notification onRoomStreamUpdate
ZegoExpressEngine.onRoomStreamUpdate = (String roomID, ZegoUpdateType updateType, List<ZegoStream> streamList, Map<String, dynamic> extendedData) {
ZegoVideoCodecID videoCodecID = ZegoVideoCodecID.Default; // Get the encoding format of this stream from the App's business server
String playStreamID = ""; // Please enter streamID
int viewID = playViewID; // viewID needed for playing stream rendering, obtained through sdk's createCanvasView
var playCanvas = ZegoCanvas(viewID);
if (videoCodecID == ZegoVideoCodecID.H265) {
// Encoding format is H.265
bool h265DecoderSupport = await ZegoExpressEngine.instance.isVideoDecoderSupported(ZegoVideoCodecID.H265);
// If decoding is not supported, do not pull stream
if (h265DecoderSupport) {
// Only pull from RTC
var config = ZegoPlayerConfig(ZegoStreamResourceMode.OnlyRTC, ZegoVideoCodecID.H265);
// Supports H.265 decoding
ZegoExpressEngine.instance.startPlayingStream(playStreamID, canvas: playCanvas, config: config);
}
}
else if (videoCodecID == ZegoVideoCodecID.Default) {
// Only pull from RTC
var config = ZegoPlayerConfig(ZegoStreamResourceMode.OnlyRTC, ZegoVideoCodecID.Default);
// Encoding format is H.264
ZegoExpressEngine.instance.startPlayingStream(playStreamID, canvas: playCanvas, config: config);
}
}Recording
If H.265 codec function is used for local server-side recording, cloud recording, and data stream recording, it will affect the generation of recording files. Details are as follows:
When recording a pushed stream (H.265 video encoded stream), encoding degradation may be triggered due to H.265 encoding failure. At this time, the onPublisherVideoEncoderChanged callback will be received, indicating that the video encoding format has changed.
In this scenario, to avoid damaging the recording file, the SDK will internally end and save the current recording task, and automatically restart a new recording task. The recording file path of the new recording task will be regenerated to avoid overwriting the original recording file. The generation rule of the new file is to add a timestamp to the original recording file name:
For example, if the original recording file path passed in by the developer is: /user/data/mediarecord.mp4, then the new recording file is: /user/data/mediarecord_1626880634948.mp4, where 1626880634948 is the current timestamp.
If the developer receives the onPublisherVideoEncoderChanged callback during recording, they need to collect other files in the recording file storage path after the recording ends.
FAQ
- What to do if H.265 hardware encoding encounters an error?
You can call the enableH265EncodeFallback interface to enable the fallback function (enabled by default). If H.265 hardware encoding fails, it will downgrade to H.264. If recording function is used at the same time, the recording files will become two copies.
- Will H.265 automatically fallback from hardware decoding to software decoding?
Yes, if hardware decoding fails during decoding, it will automatically downgrade to software decoding.
- How is H.265 charged?
Client-side enabling of H.265 function does not require fees, but stream mixing output H.265 requires stream mixing fees, which is more expensive than stream mixing output H.264. Please consult ZEGO sales personnel for details.
- Is there a change in billing when mixing H.265 streams in and outputting H.264 streams?
No change, charged based on output H.264.
- What are the hardware requirements for H.265 decoding?
Currently, all models on the market support H.265 decoding. Through testing, low-end models before 2013 may have frame rate fluctuations when decoding.
