Description
LocalCustomVideoTrack pushes external raw YUV video frames (such as a whiteboard, canvas, player output, or third-party capture source) into a published track. Get it through RTCEngine.getLocalCustomVideoTrack. It extends LocalVideoTrack and can be passed directly as the input track to publishLocalVideo / unPublishLocalVideo.
This page is the API reference; for the full integration flow, frame format conversion, and troubleshooting tips, see Custom tracks.
The input is unencoded raw YUV (I420) frames. The SDK encodes them according to the preset parameters, so you don’t need to encode them yourself.
Properties
preOpt
preOpt.publish.descdetermines the track description of this track, andinputDataalso uses it to locate the target track.- The SDK caches the track instance as a singleton: repeated calls to
getLocalCustomVideoTrack(preOpt)return the same instance and overwrite it with thepreOptyou pass. To distinguish between a “custom track” and a “screen sharing track”, republish after switching presets instead of alternating frames between twodescvalues at the same time.
LocalCustomVideoTrack methods
inputData(yuv, width, height, strideY, strideU, strideV, rotation, stamp)
preOpt.publish.desc and feeds the frame into the encoding pipeline; if the track isn’t published yet, the frame is silently dropped.Parameters:
Returns: None (
Unit).
Frame data format requirements
- Must be tightly packed I420: the
Yplane ofwidth * heightbytes, immediately followed by theUplane of(width/2) * (height/2)bytes, then aVplane of the same size, with no gaps between the three segments. stridemust match the tightly packed layout (width,width/2,width/2). The SDK currently computes plane offsets from the tightly packed layout, so passing row strides with padding causes misaligned or corrupted video. If upstream data has padding (for example, Camera2’srowStride > width), copy the valid pixels into a tightly packed array first.- If the data is too short, an
IllegalArgumentException(Invalid I420 size) is thrown before encoding. - You don’t need to align the resolution for the encoder: the SDK aligns and scales according to the device encoder’s requirements; however,
width/heightmust be even. - You control the frame pacing. The frame rate and bitrate caps are determined by
preOpt; pushing frames faster than the preset frame rate only adds unnecessary overhead.
Rendering methods inherited from VideoTrack
addPlayView / replacePlayView / removePlayView / removeAllPlayView are provided by the base class VideoTrack, with the same signatures as LocalScreenTrack.
Note: The SDK doesn’t echo frames sent through inputData to these render views (local echo only applies to camera tracks). For a local preview of custom video, draw from your data source yourself; you don’t need to add render views to this track.
Typical integration flow
TRACK_SHARE), use PreOptionCustomVideo.screen instead, or override desc with PublishCustomOptions(desc = ...) when publishing:
Notes
- Publish first, then push frames: call
inputDataonly after thepublishLocalVideosuccess callback; otherwise frames are dropped without any notice. - Keep
descconsistent: if you overridedescwithPublishCustomOptionswhen publishing, the SDK writes it back topreOpt.publish.desc, andinputDatastill locates the track by the latestdesc; don’t keep a separate copy of the olddescin your code for decisions. - Publish/unpublish callbacks are coalesced: as with the camera, when
publish/unpublishare called in rapid succession, intermediate coalesced calls may not get a callback; rely on the callback of the last call or the final state. - Republish after leaving the channel:
leave()releases the media streaming engine. The track instance remains, but its publish state is no longer valid; after joining again, you must callpublishLocalVideoagain before pushing frames.releaseSDK()also clears the local track cache, after which you need to callgetLocalCustomVideoTrackagain. - Reuse input arrays:
inputDatacopies the data into the encoding buffer internally, so you can reuse theByteArrayas soon as the call returns. A buffer pool is recommended to reduce GC pressure.