Frame
One decoded frame (video or audio), backed by an opaque native owner. Close it to release the buffers.
Ownership rule. Frames emitted by the public Flow APIs (MediaSource.decodedFrames, MediaSource.decodeStreams, FilterGraph.process) are owned by the collector. Each frame stays valid until you close it. Close every collected frame. An unclosed frame leaks its native buffers. Frames handed to a callback (FilterGraph.feedInput's onOutput) are valid only for that call. Call copy to take an owned snapshot of one.
Buffering rule. toList() is safe: every frame reaches you. Do not put frames through a channel the standard library made: buffer(), flowOn, conflate and produceIn all queue elements they cannot close, so cancelling part way through (buffer().take(1) is the ordinary case) drops whatever is still queued and leaks it. Use bufferFrames instead, which owns its channel and closes what you never receive; it takes a context for the flowOn case too.
The native representation is intentionally not exposed. Pipeline operators (FilterGraph, encoders) accept Frames directly and resolve their platform handle internally.
One decoded frame (video or audio), backed by an opaque native owner. Close it to release the buffers.
Ownership rule. Frames emitted by the public Flow APIs (MediaSource.decodedFrames, MediaSource.decodeStreams, FilterGraph.process) are owned by the collector. Each frame stays valid until you close it. Close every collected frame. An unclosed frame leaks its native buffers. Frames handed to a callback (FilterGraph.feedInput's onOutput) are valid only for that call. Call copy to take an owned snapshot of one.
Buffering rule. toList() is safe: every frame reaches you. Do not put frames through a channel the standard library made: buffer(), flowOn, conflate and produceIn all queue elements they cannot close, so cancelling part way through (buffer().take(1) is the ordinary case) drops whatever is still queued and leaks it. Use bufferFrames instead, which owns its channel and closes what you never receive; it takes a context for the flowOn case too.
The native representation is intentionally not exposed. Pipeline operators (FilterGraph, encoders) accept Frames directly and resolve their platform handle internally.
AVFrame-backed Frame implementation. The native pointer (nativeFrame) is internal: users go through info / copyPlanesToByteArray; the filter graph & encoder modules in this package read the pointer directly for zero-copy hand-offs.
Construction: see Frame.acquire (alloc) and Frame.wrap (when an existing AVFrame should be adopted, e.g. from a decoder).
One decoded frame (video or audio), backed by an opaque native owner. Close it to release the buffers.
Ownership rule. Frames emitted by the public Flow APIs (MediaSource.decodedFrames, MediaSource.decodeStreams, FilterGraph.process) are owned by the collector. Each frame stays valid until you close it. Close every collected frame. An unclosed frame leaks its native buffers. Frames handed to a callback (FilterGraph.feedInput's onOutput) are valid only for that call. Call copy to take an owned snapshot of one.
Buffering rule. toList() is safe: every frame reaches you. Do not put frames through a channel the standard library made: buffer(), flowOn, conflate and produceIn all queue elements they cannot close, so cancelling part way through (buffer().take(1) is the ordinary case) drops whatever is still queued and leaks it. Use bufferFrames instead, which owns its channel and closes what you never receive; it takes a context for the flowOn case too.
The native representation is intentionally not exposed. Pipeline operators (FilterGraph, encoders) accept Frames directly and resolve their platform handle internally.
A decoded frame, as a handle into the codec module.
The pointer is an opaque Int on this side and is never dereferenced here; every read is a call. The frame is owned: close frees it, and closing twice is a no-op because the pointer is cleared.
Types
Properties
FrameInfo.duration converted to microseconds. Null when the decoder supplied no duration. A duration is an interval, so no container start offset applies to it.
The hardware surface behind this frame, or null when its pixels are in main memory.
FrameInfo.pts converted to microseconds on the stream's own timeline. Null when the frame carries no timestamp.
Functions
An owned snapshot of this frame. Use it to keep a callback-scoped frame past that call. O(1): it takes new references to the same refcounted buffers, with no pixel copy. The returned frame survives the source being recycled. Close it yourself.
An owned snapshot of this frame. Use it to keep a callback-scoped frame past that call. O(1): it takes new references to the same refcounted buffers, with no pixel copy. The returned frame survives the source being recycled. Close it yourself.
An owned snapshot of this frame. Use it to keep a callback-scoped frame past that call. O(1): it takes new references to the same refcounted buffers, with no pixel copy. The returned frame survives the source being recycled. Close it yourself.
An owned snapshot of this frame. Use it to keep a callback-scoped frame past that call. O(1): it takes new references to the same refcounted buffers, with no pixel copy. The returned frame survives the source being recycled. Close it yourself.
Copy the frame's pixel planes (video) or samples (audio) into a flat ByteArray. Planar formats stay planar and packed formats stay packed, with no linesize padding (align=1, tightly packed). For yuv420p at WxH this returns W*H*3/2 bytes (Y plane, then U, then V); for fltp stereo it returns the left plane followed by the right. Frame.ofVideo / Frame.ofAudio accept exactly this layout back.
Copy the frame's pixel planes (video) or samples (audio) into a flat ByteArray. Planar formats stay planar and packed formats stay packed, with no linesize padding (align=1, tightly packed). For yuv420p at WxH this returns W*H*3/2 bytes (Y plane, then U, then V); for fltp stereo it returns the left plane followed by the right. Frame.ofVideo / Frame.ofAudio accept exactly this layout back.
Copy the frame's pixel planes (video) or samples (audio) into a flat ByteArray. Planar formats stay planar and packed formats stay packed, with no linesize padding (align=1, tightly packed). For yuv420p at WxH this returns W*H*3/2 bytes (Y plane, then U, then V); for fltp stereo it returns the left plane followed by the right. Frame.ofVideo / Frame.ofAudio accept exactly this layout back.
Copy the frame's pixel planes (video) or samples (audio) into a flat ByteArray. Planar formats stay planar and packed formats stay packed, with no linesize padding (align=1, tightly packed). For yuv420p at WxH this returns W*H*3/2 bytes (Y plane, then U, then V); for fltp stereo it returns the left plane followed by the right. Frame.ofVideo / Frame.ofAudio accept exactly this layout back.
Copy the frame's pixel planes (video) or samples (audio) into a flat ByteArray. Planar formats stay planar and packed formats stay packed, with no linesize padding (align=1, tightly packed). For yuv420p at WxH this returns W*H*3/2 bytes (Y plane, then U, then V); for fltp stereo it returns the left plane followed by the right. Frame.ofVideo / Frame.ofAudio accept exactly this layout back.
The measured software download of a hardware frame (window 3, S2.a): copies the pixels out of GPU memory into a new ordinary frame and carries the presentation properties (pts, colour, rotation side data) with them. This is D-2's fallback path made explicit: a renderer that cannot take the hardware surface calls this once per frame and pays the copy knowingly, which is exactly what HardwareWithDownload reports upstream.
The measured software download of a hardware frame (window 3, S2.a): copies the pixels out of GPU memory into a new ordinary frame and carries the presentation properties (pts, colour, rotation side data) with them. This is D-2's fallback path made explicit: a renderer that cannot take the hardware surface calls this once per frame and pays the copy knowingly, which is exactly what HardwareWithDownload reports upstream.
The measured software download of a hardware frame (window 3, S2.a): copies the pixels out of GPU memory into a new ordinary frame and carries the presentation properties (pts, colour, rotation side data) with them. This is D-2's fallback path made explicit: a renderer that cannot take the hardware surface calls this once per frame and pays the copy knowingly, which is exactly what HardwareWithDownload reports upstream.
The measured software download of a hardware frame (window 3, S2.a): copies the pixels out of GPU memory into a new ordinary frame and carries the presentation properties (pts, colour, rotation side data) with them. This is D-2's fallback path made explicit: a renderer that cannot take the hardware surface calls this once per frame and pays the copy knowingly, which is exactly what HardwareWithDownload reports upstream.
Refused, because no hardware frame exists on this backend: the wasm decoder is software by construction, so every frame here is already the software one this would produce.
Encode this (video) frame as a standalone compressed image: MJPEG (.jpg) by default, or CodecId.Png. This converts the pixel format automatically when the image codec does not accept the frame's own (e.g. yuv420p → rgb24 for PNG). It leaves this frame untouched, timestamp included, so a frame can be thumbnailed and still encoded into a video.
Encode this (video) frame as a standalone compressed image: MJPEG (.jpg) by default, or CodecId.Png. This converts the pixel format automatically when the image codec does not accept the frame's own (e.g. yuv420p → rgb24 for PNG). It leaves this frame untouched, timestamp included, so a frame can be thumbnailed and still encoded into a video.
Encode this (video) frame as a standalone compressed image: MJPEG (.jpg) by default, or CodecId.Png. This converts the pixel format automatically when the image codec does not accept the frame's own (e.g. yuv420p → rgb24 for PNG). It leaves this frame untouched, timestamp included, so a frame can be thumbnailed and still encoded into a video.
Encode this (video) frame as a standalone compressed image: MJPEG (.jpg) by default, or CodecId.Png. This converts the pixel format automatically when the image codec does not accept the frame's own (e.g. yuv420p → rgb24 for PNG). It leaves this frame untouched, timestamp included, so a frame can be thumbnailed and still encoded into a video.
Encode this (video) frame as a standalone compressed image: MJPEG (.jpg) by default, or CodecId.Png. This converts the pixel format automatically when the image codec does not accept the frame's own (e.g. yuv420p → rgb24 for PNG). It leaves this frame untouched, timestamp included, so a frame can be thumbnailed and still encoded into a video.