H.265
Feature Overview
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 during encoding or stream mixing.
- 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 SDK versions to 2.12.0 or above, otherwise the online version may experience anomalies when decoding H.265.
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 device models support hardware encoding and decoding. | Most device models support hardware encoding, and the vast majority of device models support hardware decoding. |
| Stream mixing output | Supported. | Supported, but the price is more expensive than H.264 stream mixing output. For details, please consult ZEGO business personnel. |
| Applicable scenarios | All scenarios. | Recommended for live streaming and audio/video interactive scenarios. |
Application Scenarios
H.265 encoding can be used in the following application scenarios:
| Application Scenario Type | Description |
|---|---|
| Show live streaming, e-commerce live streaming, interactive live streaming, gaming live streaming | Through H.265 encoding, reduce the bitrate by 30% (measured value) and distribute to thousands of viewers, greatly reducing CDN distribution costs. |
| Video call, video conference, online education | Through H.265 encoding, improve picture clarity at the same bitrate, making call effects better in these scenarios. |
Currently, Web and Mini Program platforms do not support 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 and video streams from the cloud into one stream. It supports three methods: manual stream mixing, automatic stream mixing, and fully automatic stream mixing. For details, please refer to Stream Mixing.
- Forward to CDN: The process of pushing audio and video streams from ZEGO audio and video cloud to CDN. For details, please refer to Publish/Play Streams via CDN.
- Co-hosting: A form of interaction between users in a room. By pushing your own stream through the startPublishingStream interface while calling the startPlayingStream interface to pull the other party's stream, two users can engage in interactive calls after successfully co-hosting.
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 business personnel for specific pricing information.
Example Source Code Download
Please refer to Download Example Source Code to obtain the source code.
For related source code, please check the files in the “/ZegoExpressExample/Examples/AdvancedStreaming/H265” directory.
Prerequisites
Before using the H.265 encoding and decoding feature, please ensure:
- You have created a project in the ZEGO Console and applied for a valid AppID and AppSign. For details, please refer to Console - Project Information.
- You have integrated ZEGO Express SDK in your project and implemented basic audio and video streaming functionality. For details, please refer to Quick Start - Integration and Quick Start - Implementation.
Implementation Method
Detect H.265 Encoding and Decoding Capabilities
Detect H.265 Encoding Capability
Some older or low-end mobile device models do not support H.265 video encoding. In this case, developers need to determine whether the local device supports H.265 video encoding capability through the isVideoEncoderSupported interface before streaming. Only if supported, the H.265 video encoding type can be set through the setVideoConfig interface before streaming, otherwise it will not take effect.
Detect H.265 Decoding Capability
Some older or low-end mobile device models do not support H.265 video decoding. In scenarios that support pulling different video streams, such as CDN scenarios, developers need to determine whether the local device supports H.265 video decoding capability through the isVideoDecoderSupported interface before playing stream. Only if supported, H.265 video streams can be pulled, otherwise only other format video streams can be pulled, such as H.264.
Co-hosting Stream Mixing Live Streaming
Co-hosting stream mixing live streaming includes the following two implementation methods. Developers can integrate as needed according to the actual situation:
- Mix out 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 in the stream mixing service, without the need for CDN transcoding. Compared with stream mixing pushing to CDN for transcoding, it has higher clarity and lower cost, so it is recommended.
- Stream mixing pushes to CDN for transcoding: The stream mixing service directly outputs one H.265 mixed stream, which needs to be transcoded by the 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.
Mix out streams of different formats (recommended)
In this scenario, after the stream mixing service receives the streams from the host and co-hosting guests through ZEGOCLOUD, it directly outputs one H.265 mixed stream and one H.264 mixed stream, and pushes both streams to the CDN. The audience can choose to pull H.265 streams or H.264 streams from the CDN according to whether their terminal devices support H.265 video decoding.

-
Host Side
- Create a new stream mixing task object through the constructor ZegoMixerTask, and then call instance methods to set input, output and other parameters respectively.
- Set the input stream list for the stream mixing task through the inputList property in the stream mixing task object ZegoMixerTask (the encoding formats of streams in stream mixing input support H.264 and H.265), and supports up to 9 input streams by default. Please handle the stream layout yourself.
- Set the output stream list for the stream mixing task through the outputList property in the stream mixing task object ZegoMixerTask. Assuming the current scenario, the stream mixing service directly transcodes out 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 the stream mixing task.
- The developer notifies the app's business server that the stream has been added.
// Call startMixerTask to initiate stream mixing // Please enter taskID std::string taskID = “”; ZegoMixerTask task(mixerTaskID); // Please set videoConfig yourself ZegoMixerVideoConfig videoConfig; videoConfig.fps = 15; videoConfig.height = 720; videoConfig.width = 1280; task.videoConfig = videoConfig; ZegoMixerAudioConfig audioConfig; task.audioConfig = audioConfig; // Note, the encoding formats of streams in stream mixing input support H.264 and H.265, please handle stream layout and input yourself task.inputList = {}; // Stream mixing two outputs // Note: The output target can be streamID or CDN address, the two are handled differently on the audience side, in this scenario it is recommended to directly pass in stremaID // Note: The bitrate in ZegoMixerOutput has higher priority than the bitrate in ZegoMixerVideoConfig std::string h264StreamID = “”; // Please enter h264StreamID std::string h265StreamID = “”; // Please enter h265StreamID // Please enter h264 bitrate, this bitrate is the recommended bitrate for the current resolution and frame rate (720p, 15fps) int h264Bitrate = 2244; // Please enter h265 bitrate, this bitrate is the recommended bitrate for the current resolution and frame rate (720p, 15fps) int h265Bitrate = 1795; // H.264 target ZegoMixerOutput mixer_output_h264; mixer_output_h264.target = h264StreamID; mixer_output_h264.videoConfig.bitrate = h264Bitrate; mixer_output_h264.videoConfig.videoCodecID = ZegoVideoCodecID::ZEGO_VIDEO_CODEC_ID_SVC; // H.265 target ZegoMixerOutput mixer_output_h265; mixer_output_h265.target = h265StreamID; mixer_output_h265.videoConfig.bitrate = h265Bitrate; mixer_output_h265.videoConfig.videoCodecID = ZegoVideoCodecID::ZEGO_VIDEO_CODEC_ID_H265; task.outputList = { mixer_output_h264, mixer_output_h265 }; engine->startMixerTask(task, [=](int errorCode, std::string extendData){ // Stream mixing task callback }); // The developer notifies the app's business server that the stream has been added -
Audience Side
- The audience side receives a stream addition notification from the app's business server.
- Call the isVideoDecoderSupported interface to query whether the audience side's own device supports H.265 decoding format.
- If supported, call the startPlayingStream interface to pull H.265 streams from the CDN.
- If not supported, call the startPlayingStream interface to pull H.264 streams from the CDN.
// Receive stream addition notification from the app's business server bool h265DecodeSupport = engine->isVideoDecoderSupported(ZegoVideoCodecID::ZEGO_VIDEO_CODEC_ID_H265);; // h264StreamID std::string h264StreamID = ""; // h265StreamID std::string h265StreamID = ""; //winId is the window handle ZegoCanvas canvas((void*)ui->playView->winId()); if (h265DecodeSupport) { // Supports H.265 decoding engine->startPlayingStream(h265StreamID, &canvas); } else { // Does not support H.265 decoding engine->startPlayingStream(h264StreamID, &canvas); }
Stream mixing then push to CDN for transcoding
In this scenario, after the stream mixing service receives the streams from the host and co-hosting guests through ZEGOCLOUD, it directly outputs one H.265 mixed stream and pushes this mixed stream to the CDN. Through the CDN's transcoding capability, the audience can choose to pull H.265 streams or H.264 streams from the CDN according to whether their terminal devices support H.265 video decoding.

-
Host Side
- Create a new stream mixing task object through the constructor ZegoMixerTask, and then call instance methods to set input, output and other parameters respectively.
- Set the input stream list for the stream mixing task through the inputList property in the stream mixing task object ZegoMixerTask (the encoding formats of streams in stream mixing input support H.264 and H.265), and supports up to 9 input streams by default. Please handle the stream layout yourself.
- Set the output stream list for the stream mixing task through the outputList property in the stream mixing task object ZegoMixerTask. Assuming 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 the stream mixing task.
- The developer notifies the app's business server that the stream has been added.
// Call startMixerTask to initiate stream mixing // Please enter taskID std::string taskID = ""; ZegoMixerTask task(mixerTaskID); // Please set videoConfig ZegoMixerVideoConfig videoConfig; videoConfig.fps = 15; videoConfig.height = 720; videoConfig.width = 1280; task.videoConfig = videoConfig; ZegoMixerAudioConfig audioConfig; task.audioConfig = audioConfig; // Note, the encoding formats of streams in stream mixing input support H.264 and H.265 task.inputList = {}; // Please enter CDN URL std::string publishCdnUrl = ""; // Please enter h265 bitrate, this bitrate is the recommended bitrate for the current resolution and frame rate (720p, 15fps) int h265Bitrate = 1795; // Note, since CDN transcoding is required here, the target needs to be passed in as CDN URL ZegoMixerOutput outputH265; outputH265.target = publishCdnUrl; outputH265.videoConfig.bitrate = h265Bitrate; outputH265.videoConfig.videoCodecID = ZegoVideoCodecID::ZEGO_VIDEO_CODEC_ID_H265; task.outputList = { outputH265 }; engine->startMixerTask(task, [=](int errorCode, std::string extendData){ // Stream mixing task callback }); // The developer notifies the app's business server that the stream has been added -
Audience Side
- The audience side receives a stream addition notification from the app's business server.
- Call the isVideoDecoderSupported interface to query whether the audience side's own device supports H.265 decoding format.
- If supported, call the startPlayingStream interface to pull H.265 streams from the CDN.
- If not supported, call the startPlayingStream interface to pull H.264 streams from the CDN.
// Receive stream addition notification from the app's business server bool h265DecodeSupport = engine->isVideoDecoderSupported(ZegoVideoCodecID::ZEGO_VIDEO_CODEC_ID_H265);; std::string playStreamID = ""; //winId is the window handle ZegoCanvas canvas((void*)ui->playView->winId()); if (h265DecodeSupport) { // Supports H.265 decoding // Please fill in the H.265 URL address std::string h265Url = ""; // Note: ZegoCDNConfig and ZegoPlayerConfig have other configurable options ZegoCDNConfig cdnConfig; // H.265 CDN playing address cdnConfig.url = h265Url; ZegoPlayerConfig playerConfig; playerConfig.cdnConfig = &cdnConfig; engine->startPlayingStream(playStreamID, &canvas, playerConfig); } else { // Does not support H.265 decoding // Please fill in the H264 URL address std::string h264Url = ""; // Note: ZegoCDNConfig and ZegoPlayerConfig have other configurable options ZegoCDNConfig cdnConfig; // H.264 CDN playing address cdnConfig.url = h264Url; ZegoPlayerConfig playerConfig; playerConfig.cdnConfig = &cdnConfig; engine->startPlayingStream(playStreamID, &canvas, playerConfig); }
Single Host Live Streaming
Real-time Network Forward to CDN Live Streaming
This scenario has the following two characteristics:
- The host forwards to the CDN through ZEGOCLOUD. Through the CDN's transcoding capability, the audience can choose to pull H.265 streams or H.264 streams from the CDN according to whether their terminal devices support H.265 video decoding.
- When the host pushes H.265 streams, co-hosting guests pull streams directly from ZEGOCLOUD for real-time interaction. In this case, it is required that the co-hosting guests' terminal devices 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 streaming, it will take effect only from the next streaming). After enabling, GPU will be used for encoding, reducing CPU usage.
Call the isVideoEncoderSupported interface to query whether the host side device supports the specified video encoding type.
Before streaming, call the setVideoConfig interface to set the video encoding format through codecID (if the configuration is changed after streaming, it will take effect only from the next streaming). If H.265 encoding is set, then:
You can call the enableH265EncodeFallback interface to enable automatic fallback 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 try to downgrade to use H.264 encoding for streaming. After disabling, when H.265 encoding is not supported or H.265 encoding fails, streaming will directly fail.
Call the addPublishCdnUrl interface to add the URL address for forwarding the audio and video streams from ZEGOCLOUD to the CDN.
Call the startPublishingStream interface to start streaming. After streaming is successful, other users in the same room can get the stream addition status by listening to the onRoomStreamUpdate callback.
The developer notifies the app's business server of the encoding format of this stream, so that the playing side can make corresponding processing according to different streaming encoding formats.
// Mobile devices using H.265 encoding need to enable hardware encoding
engine->enableHardwareEncoder(true);
PrintLogToView("enableH265EncodeFallback:1");
engine->enableH265EncodeFallback(true);
// Query whether H.265 encoding is supported
bool h265EncoderSupport = engine->isVideoEncoderSupported(ZegoVideoCodecID::ZEGO_VIDEO_CODEC_ID_H265);;
ZegoVideoConfig videoConfig;
if (h265EncoderSupport) {
// Supports H.265 encoding
videoConfig.codecID = ZegoVideoCodecID::ZEGO_VIDEO_CODEC_ID_H265;
} else {
// Does not support H.265 encoding
videoConfig.codecID = ZegoVideoCodecID::ZEGO_VIDEO_CODEC_ID_DEFAULT;
}
engine->setVideoConfig(videoConfig);
if (h265EncoderSupport) {
// Choose whether to enable H.265 encoding failure automatic fallback capability through enableH265EncodeFallback
engine->enableH265EncodeFallback(true);
}
// Please enter streamID
std::string publishStreamID = "";
// Please enter CdnUrl
std::string publishCdnUrl = "";
// Add CDN forwarding address
engine->addPublishCdnUrl(publishStreamID, publishCdnUrl, [](int errorCode){
// Determine whether the forwarding CDN address was added successfully
});
engine->startPublishingStream(publishStreamID);
// The developer notifies the app's business server of the encoding format of this stream, so that the playing side can make corresponding processing according to different streaming encoding formats-
Audience Side
- After the host starts streaming, the audience side receives a stream addition notification through the onRoomStreamUpdate interface.
- The audience side obtains the encoding format of this 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 the CDN.
- If it is H.265 format, they need to first call the isVideoDecoderSupported interface to query whether the audience side's own device supports H.265 decoding format.
- If supported, call the startPlayingStream interface to pull H.265 streams from the CDN.
- If not supported, call the startPlayingStream interface to pull H.264 streams from the CDN.
//Receive stream addition notification onRoomStreamUpdate void H265::onRoomStreamUpdate(const std::string ¤tRoomID, ZegoUpdateType updateType, const std::vector<ZegoStream> &streamList) { // Obtain the encoding format of this stream from the app's business server int videoCodecID = 0; // Please enter streamID std::string playStreamID = ""; //winId is the window handle ZegoCanvas canvas((void*)ui->playView->winId()); if (videoCodecID == ZegoVideoCodecID::ZEGO_VIDEO_CODEC_ID_H265) { // Encoding format is H.265, specific fallback strategy needs to be coordinated with advanced playing BOOL h265DecoderSupport = engine->isVideoDecoderSupported(ZegoVideoCodecID::ZEGO_VIDEO_CODEC_ID_H265); if (h265DecoderSupport) { // Supports H.265 decoding // Please fill in the H.265 URL address std::string h265Url = ""; // Note: ZegoCDNConfig and ZegoPlayerConfig have other configurable options ZegoCDNConfig cdnConfig; // H.265 CDN playing address cdnConfig.url = h265Url; ZegoPlayerConfig playerConfig; playerConfig.cdnConfig = &cdnConfig; engine->startPlayingStream(playStreamID, &canvas, playerConfig); } else { // Does not support H.265 decoding // Please fill in the H264 URL address std::string h264Url = ""; // Note: ZegoCDNConfig and ZegoPlayerConfig have other configurable options ZegoCDNConfig cdnConfig; // H.264 CDN playing address cdnConfig.url = h264Url; ZegoPlayerConfig playerConfig; playerConfig.cdnConfig = &cdnConfig; engine->startPlayingStream(playStreamID, &canvas, playerConfig); } } else if (videoCodecID == ZegoVideoCodecID::ZEGO_VIDEO_CODEC_ID_DEFAULT) { // Encoding format is H.264 engine->startPlayingStream(playStreamID, canvas); } } -
Co-hosting Guest Side
- After the host starts streaming, the co-hosting guest receives a stream addition notification through the onRoomStreamUpdate interface.
- The co-hosting guest obtains the encoding format of this stream from the app's business server.
- If it is H.264 format, the co-hosting guest can call the startPlayingStream interface to pull the host's stream directly from ZEGOCLOUD.
- If it is H.265 format, they need to first call the isVideoDecoderSupported interface to query whether their own device supports H.265 decoding format.
- If supported, call the startPlayingStream interface to pull H.265 streams from ZEGOCLOUD.
- If not supported, prompt that this terminal device does not support pulling this stream.
//Receive stream addition notification onRoomStreamUpdate void H265::onRoomStreamUpdate(const std::string ¤tRoomID, ZegoUpdateType updateType, const std::vector<ZegoStream> &streamList) { // Obtain the encoding format of this stream from the app's business server int videoCodecID = 0; // Please enter streamID std::string playStreamID = ""; //winId is the window handle ZegoCanvas canvas((void*)ui->playView->winId()); ZegoPlayerConfig playerConfig; playerConfig.resourceMode = ZEGO_STREAM_RESOURCE_MODE_ONLY_RTC; // Only pull streams from RTC if (videoCodecID == ZegoVideoCodecID::ZEGO_VIDEO_CODEC_ID_H265) { // Encoding format is H.265, specific fallback strategy needs to be coordinated with advanced playing bool h265DecoderSupport = engine_->isVideoDecoderSupported(ZegoVideoCodecID::ZEGO_VIDEO_CODEC_ID_H265); if (h265DecoderSupport) { // Supports H.265 decoding engine_->startPlayingStream(playStreamID, &canvas, playerConfig); } } else if (videoCodecID == ZegoVideoCodecID::ZEGO_VIDEO_CODEC_ID_DEFAULT) { // Encoding format is H.264 engine_->startPlayingStream(playStreamID, &canvas, playerConfig); } }
Recording
If you use H.265 encoding and decoding functionality when performing local server recording, cloud recording, or data stream recording, it will affect the generation of recording files. Details are as follows:
When recording streams (H.265 video encoded streams), encoding downgrade may be triggered due to H.265 encoding failure. At this time, you will receive the onPublisherVideoEncoderChanged callback, indicating that the video encoding format has changed.
In this scenario, to avoid damaging the recording files, 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 new file generation rule 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 has received the onPublisherVideoEncoderChanged callback during recording, they need to collect other files in the recording file storage path after 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 you are using the recording function at the same time, the recording files will become two copies.
- Will H.265 automatically downgrade from hardware decoding to software decoding?
Yes, if hardware decoding fails during decoding, it will automatically downgrade to software decoding.
- How is H.265 priced?
Enabling H.265 functionality on the client side does not require additional fees, but stream mixing output H.265 requires stream mixing fees, which is more expensive than stream mixing output H.264. For details, please consult ZEGO business personnel.
- Is there any change in billing when mixing H.265 stream input and H.264 stream output?
No change, billing is based on H.264 output.
- What are the hardware requirements for H.265 decoding?
Currently, all device models on the market support H.265 decoding. Testing shows that low-end device models from before 2013 may experience frame rate fluctuations during decoding.
