Class VideoFrame.Writer
- Enclosing class:
VideoFrame
A nested class rather than package-private methods on purpose: producers live in other packages and other modules, and package-private access across a module boundary requires a split package, which fails as soon as anything declares a module descriptor. A nested class reaches the frame's private state from anywhere.
One thread per slot: only the thread that owns the pool calls these. The steady-state path
is setPtsMicros(long) then publish(): two primitive writes, nothing
created. configure(int, int, limn.video.PixelFormat, limn.video.VideoColor) and setPlane(int, java.nio.ByteBuffer, int) are for pool construction and for a format
change; calling them per picture is the mistake that reintroduces per-frame allocation.
-
Method Summary
Modifier and TypeMethodDescriptionstatic VideoFrame.Writerallocate(int slot, VideoFrame.Recycler recycler) Builds one pooled frame and the writer that publishes it.voidconfigure(int width, int height, PixelFormat format, VideoColor color) Sets geometry and interpretation and invalidates every plane binding, sosetPlane(int, java.nio.ByteBuffer, int)must be called for all of the format's planes before the nextpublish().voidEnds aVideoFrame.Downloader's work: the planes it has just bound become the picture, and this frame stops being handle-backed for the rest of the lease the consumer is holding.frame()publish()Rewinds every plane view, marks the frame held and returns it for handoff.voidsetDownloader(VideoFrame.Downloader downloader) Installs the producer's way of reading one of its device pictures back into memory, for the consumers that cannot use a handle.voidsetHandle(VideoFrame.Kind kind, long handle) Makes the nextpublish()a device picture rather than a planar one: this frame will carryhandle,VideoFrame.plane(int)will refuse, and every plane binding is dropped.voidsetPlane(int plane, ByteBuffer buffer, int strideBytes) Pointsplaneatbuffer, whose rows arestrideBytesapart.voidsetPtsMicros(long ptsMicros) Sets the presentation time in microseconds from the start of the stream, orVideoFrame.PTS_UNKNOWNwhen the producer has no timing at all.
-
Method Details
-
allocate
Builds one pooled frame and the writer that publishes it. Pool construction only.- Parameters:
slot- this frame's index in the pool, at least 0recycler- whereVideoFrame.release()returns the memory- Throws:
IllegalArgumentException- ifslotis negativeNullPointerException- ifrecycleris null
-
frame
- Returns:
- the frame this writer publishes, the same instance for the pool's lifetime
-
configure
Sets geometry and interpretation and invalidates every plane binding, sosetPlane(int, java.nio.ByteBuffer, int)must be called for all of the format's planes before the nextpublish().- Parameters:
width- visible width in pixels, in[1..PixelFormat.MAX_DIMENSION]height- visible height in pixels, in the same range- Throws:
IllegalArgumentException- if either dimension is outside that rangeIllegalStateException- if the frame is currently publishedNullPointerException- ifformatorcoloris null
-
setPlane
Pointsplaneatbuffer, whose rows arestrideBytesapart. The buffer is stored as a read-only view; its capacity must be at least the plane's minimum byte count for the configured size and this stride, and may be more; a frame cropped out of a larger coded picture is expressed exactly this way, by slicing each plane so byte 0 is the first visible sample and leaving the stride at the coded width.Direct or heap: the toolkit reads either. A consumer that uploads to a device may require direct, which is that consumer's precondition and not this one's.
- Parameters:
strideBytes- bytes between the starts of consecutive rows; rows run top-down, so a producer holding bottom-up rows flips on its own side- Throws:
IllegalArgumentException- if the stride is below the plane's byte width, or the buffer is smaller than the plane needsIllegalStateException- if the frame is currently published (except inside aVideoFrame.Downloader, which is the one moment a producer may re-point a held frame), or if no size has been configured yetIndexOutOfBoundsException- ifplaneis not a plane of the configured formatNullPointerException- ifbufferis null
-
setPtsMicros
public void setPtsMicros(long ptsMicros) Sets the presentation time in microseconds from the start of the stream, orVideoFrame.PTS_UNKNOWNwhen the producer has no timing at all. SurvivesVideoFrame.release(), so a producer that does not set it per picture republishes the previous one. -
setHandle
Makes the nextpublish()a device picture rather than a planar one: this frame will carryhandle,VideoFrame.plane(int)will refuse, and every plane binding is dropped.The geometry and the
PixelFormatstill describe the picture (a VideoToolbox NV12 surface is NV12, and the layout is what a consumer needs to bind or convert it), but the samples are not in memory this side can address.Set per picture, unlike
setPlane(int, java.nio.ByteBuffer, int): a decoder's pool hands out a different allocation each time, and a handle is one field rather than a read-only view, so writing it per picture allocates nothing.- Parameters:
kind- which family of handle this is; notVideoFrame.Kind.PLANARhandle- the device allocation, not 0- Throws:
IllegalArgumentException- ifkindisVideoFrame.Kind.PLANARorhandleis 0IllegalStateException- if the frame is currently publishedNullPointerException- ifkindis null
-
setDownloader
Installs the producer's way of reading one of its device pictures back into memory, for the consumers that cannot use a handle. Pool construction; a producer that publishes only planar pictures never calls it, andVideoFrame.toPlanar()then refuses rather than pretending.- Parameters:
downloader- whatVideoFrame.toPlanar()calls; null removes it
-
downloaded
public void downloaded()Ends aVideoFrame.Downloader's work: the planes it has just bound become the picture, and this frame stops being handle-backed for the rest of the lease the consumer is holding.- Throws:
IllegalStateException- if called outside a download, or a plane is still unbound
-
publish
Rewinds every plane view, marks the frame held and returns it for handoff. The generation counter is written last and is written volatile, so a consumer that readsVideoFrame.generation()before anything else sees a fully initialized frame even when the handoff itself carries no ordering of its own.- Returns:
- the frame, now held by whoever receives it
- Throws:
IllegalStateException- if the frame is already published, or carries neither every plane of its format nor a device handle
-