Interface VideoStreamSource
- All Superinterfaces:
AutoCloseable
VideoDecoder and driven one picture at a time.
A consumer cannot supply the destination: one 1080p picture in 4:2:0 is about 3.1 MB, and
handing out a fresh one per picture is roughly 93 MB a second of garbage at 30 per second.
Pictures are therefore owned by the source and pooled; readFrame() says what happened
and frame() lends the result, which the consumer returns with
VideoFrame.release(). Nothing on this path allocates.
Every metadata accessor (width(), height(), pixelFormat(),
color(), rotationDegrees(), frameRateNum(), frameRateDen(),
durationMicros(), canReset() and canSeek()) is fixed when the source
is opened, never changes, and is readable from any thread. A source that cannot answer them
before its first picture is decoded is not a valid implementation: a view has to be laid out
before a picture exists.
Threading: after a player takes ownership, readFrame(), reset(),
seek(long, SeekMode) and the final close() come from that player's single
decode thread, never concurrently, serialized by the player. Implementations need no
synchronization but must not assume any particular thread. The metadata accessors are the
exception: they are read concurrently and must therefore be final state rather than lazily
computed. readFrame() may block for a whole decode and must never be called on a thread
that is drawing, and seek(long, SeekMode) may block for as long as a read does.
-
Nested Class Summary
Nested ClassesModifier and TypeInterfaceDescriptionstatic enumThe outcome of areadFrame()call.static enumHow close to the target aseekis asked to land. -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final longWhatdurationMicros()reports when the length is not knowable. -
Method Summary
Modifier and TypeMethodDescriptiondefault booleancanReset()default booleancanSeek()voidclose()Releases decoder and input resources and invalidates every pooled picture.color()default longframe()The picture most recently produced byreadFrame(), on loan.intintNumerator of the nominal frame rate, kept as a rational so that rates like 30000/1001 are exact; a rate held as a fraction of a second drifts by a whole picture every few minutes.intheight()Decodes the next picture.voidreset()Rewinds to the first picture: how a player loops seamlessly, and the only repositioning this interface defines.default intHow far the picture must be turned clockwise to be displayed the right way up.default voidseek(long micros, VideoStreamSource.SeekMode mode) Moves tomicrosso that the nextreadFrame()produces a picture there.intwidth()
-
Field Details
-
DURATION_UNKNOWN
static final long DURATION_UNKNOWNWhatdurationMicros()reports when the length is not knowable.- See Also:
-
-
Method Details
-
width
int width()- Returns:
- width in pixels of the luma plane
-
height
int height()- Returns:
- height in pixels of the luma plane
-
pixelFormat
PixelFormat pixelFormat()- Returns:
- the plane layout every picture from this source uses
-
color
VideoColor color()- Returns:
- how every picture from this source is to be interpreted; never null
-
rotationDegrees
default int rotationDegrees()How far the picture must be turned clockwise to be displayed the right way up. Every recording made on a device that can be held sideways carries this, stored one way and meant to be seen another, and a consumer that ignores it shows a portrait recording on its side.The samples are not turned:
width()andheight()describe the picture as it is stored and every plane's geometry follows them, so at 90 or 270 the displayed width isheight()and the displayed height iswidth(). A consumer that lays out a box for this stream swaps them; one that only uploads planes ignores this entirely.- Returns:
- 0, 90, 180 or 270, and nothing else. An implementation whose input describes a flip, a shear or an angle off the quarter turns reports 0 rather than the nearest right angle, because a picture silently shown mirrored is worse than one shown as stored.
-
frameRateNum
int frameRateNum()Numerator of the nominal frame rate, kept as a rational so that rates like 30000/1001 are exact; a rate held as a fraction of a second drifts by a whole picture every few minutes. Nominal means what to expect, not what will arrive: a source whose pictures are unevenly spaced still reports its nominal rate here and puts the truth in each picture's timestamp.- Returns:
- the numerator, or 0 when the rate is unknown
-
frameRateDen
int frameRateDen()- Returns:
- denominator of the nominal frame rate; never 0, so a caller may always divide
-
durationMicros
default long durationMicros()- Returns:
- total length in microseconds, or
DURATION_UNKNOWNwhen the source cannot know it: a pipe, a live input, a container without a duration. Never an estimate presented as a fact.
-
readFrame
VideoStreamSource.Read readFrame()Decodes the next picture.- Returns:
- what happened; on
VideoStreamSource.Read.FRAMEthe picture is inframe() - Throws:
RuntimeException- if the stream is malformed or the decode fails. A failed read is exceptional rather than a status, so the steady-state path carries no error object; a source that can skip a damaged picture skips it and returns the next one instead of throwing.
-
frame
VideoFrame frame()The picture most recently produced byreadFrame(), on loan. The source may not refill that slot until the consumer hands it back withVideoFrame.release(), so exactly one release per delivered picture is still the rule here.After
VideoStreamSource.Read.ENDthis keeps returning that same picture, because no further ones are produced. A player that wants the final image left on screen therefore simply does not release it until it is finished with it, which costs nothing: no slot the source still needs is being withheld.- Returns:
- the borrowed picture, or null before the first
VideoStreamSource.Read.FRAMEand afterclose()
-
reset
void reset()Rewinds to the first picture: how a player loops seamlessly, and the only repositioning this interface defines. Not a seek: no time, no accuracy mode, no failure short of the input being unable to rewind at all.- Throws:
UnsupportedOperationException- ifcanReset()is false
-
canReset
default boolean canReset()- Returns:
- whether
reset()works. Asked before playback starts, so a player decides up front whether to offer looping rather than discovering it by catching an exception at the end of the input, which reaches the viewer as a stall.
-
seek
Moves tomicrosso that the nextreadFrame()produces a picture there. Unlikereset()this is a position on the same timeline the pictures' presentation times are on, so seeking to a picture's ownptsMicros()inVideoStreamSource.SeekMode.EXACTproduces that picture.What the next picture's timestamp is. In
VideoStreamSource.SeekMode.EXACTit is the first at or aftermicros, under one picture interval late, never early. InVideoStreamSource.SeekMode.KEYFRAMEit is at or beforemicros, by however much the input's own structure imposes, which for a source whose every picture is independently decodable is nothing at all. Neither mode promises a picture exactly atmicros: a picture exists at the instants the producer put one, and asking for a time between two of them cannot conjure a third.Past the end is a position, not an error. A target beyond the last picture leaves the source at the end, and the next read reports
VideoStreamSource.Read.END. A target at or below the first picture's time leaves the source at the beginning. Negative targets are the caller's mistake and are refused.What it costs.
VideoStreamSource.SeekMode.KEYFRAMEdecodes nothing.VideoStreamSource.SeekMode.EXACTdecodes and discards every picture between the nearest independently decodable one and the target, so it is bounded by the input's structure rather than by the distance travelled; a seek of one second can cost more than a seek of one minute.Pictures already lent out survive. This does not invalidate a picture the consumer is holding, and every one of them must still be released exactly once. A consumer that holds every pooled slot across a seek gets
VideoStreamSource.Read.PENDINGafterwards, exactly as it would without one.Called on the same thread as
readFrame()and never concurrently with it.- Parameters:
micros- where to move to, in microseconds on the pictures' own timeline; not negativemode- how close to land, and therefore what this costs- Throws:
UnsupportedOperationException- ifcanSeek()is falseIllegalArgumentException- ifmicrosis negativeRuntimeException- if the input could not be repositioned, which is a failure of the input rather than a property of the source and is therefore thrown rather than reported bycanSeek()
-
canSeek
default boolean canSeek()- Returns:
- whether
seek(long, SeekMode)works, which defaults to false so that a source written before seeking existed keeps telling the truth. Asked before a transport control is offered, so that a scrub bar a stream cannot honour is disabled rather than throwing under the viewer's finger. Independent ofcanReset(): an input that can be rewound to its start need not be able to reach the middle.
-
close
void close()Releases decoder and input resources and invalidates every pooled picture. Idempotent. Afterwardsframe()is null andreadFrame()reports the end, so a cleanup block needs no ordering care. A picture a consumer kept across this call refers to storage that no longer exists; copy before closing, never after.- Specified by:
closein interfaceAutoCloseable
-