|
arduino-audio-tools
|
Transparent write() wrapper that measures throughput/turnaround while forwarding every call unchanged to the target given in the constructor - drop it into a pipeline slot (e.g. h264Decoder.setOutput( meter) instead of h264Decoder.setOutput(tftOutput), with meter wrapping tftOutput) to find out how that one stage is actually performing, without instrumenting the stage itself. More...
#include <Video.h>
Classes | |
| class | PrintView |
Public Member Functions | |
| VideoFrameMeter (Print &target) | |
| VideoFrameMeter (VideoOutput &target) | |
| Print & | asPrint () |
| uint32_t | count () const |
| Total number of write() calls forwarded so far. | |
| void | flush () override |
| float | fpsAvg () const |
| float | fpsMax () const |
| virtual uint32_t | getWriteTimeMs () const |
| Optional: returns the time (ms) spent in the last write() call. | |
| virtual bool | hadOutput () const |
| virtual bool | isKeyFrame (const uint8_t *data, size_t len) |
| void | setSkipRender (bool skip) override |
| float | timeTurnaroundMs () const |
| float | timeWriteMs () const |
| size_t | write (const uint8_t *data, size_t len) override |
Protected Attributes | |
| uint32_t | count_ = 0 |
| bool | has_last_call = false |
| uint32_t | last_call_ms = 0 |
| Print * | p_target = nullptr |
| VideoOutput * | p_target_video = nullptr |
| PrintView | print_view_ {*this} |
| uint32_t | total_forward_ms = 0 |
| uint32_t | total_turnaround_ms = 0 |
Transparent write() wrapper that measures throughput/turnaround while forwarding every call unchanged to the target given in the constructor - drop it into a pipeline slot (e.g. h264Decoder.setOutput( meter) instead of h264Decoder.setOutput(tftOutput), with meter wrapping tftOutput) to find out how that one stage is actually performing, without instrumenting the stage itself.
Derives from VideoOutput only (not also Print - see asPrint() for why), so it can be passed directly wherever a VideoOutput& is expected; for a plain Print& target/slot, use asPrint() instead of the object itself.
Tracks, as running averages since construction:
|
inline |
| target | every write() call is forwarded here, unmodified. |
|
inline |
| target | every write() call is forwarded here, unmodified - AND flush()/setSkipRender() are also forwarded, so a meter dropped in front of a VideoOutput (e.g. wrapping tftOutput in h264Decoder. setOutput(meter) instead of h264Decoder.setOutput(tftOutput)) stays transparent to a pipeline's render-skip hint instead of silently breaking it - the Print-only constructor above can't do that, since Print has no equivalent call to forward. |
|
inline |
A Print-compatible view onto this meter - use this (e.g. someSink.setOutput(meter.asPrint())) at any call site that specifically needs a Print& rather than a VideoOutput&. Never pass the meter itself there: VideoFrameMeter derives only from VideoOutput precisely so it stays unambiguous wherever an API (this codebase has several - DemuxerAVI::setOutputVideo(), H264Decoder::setOutput(), ...) is overloaded on both Print& and VideoOutput& - a type implicitly convertible to both would make every such call ambiguous.
|
inline |
Total number of write() calls forwarded so far.
|
inlineoverridevirtual |
Finalizes the frame most recently written via one or more write() calls - see class comment. Default no-op for implementations that display/decode synchronously in write() instead.
Reimplemented from VideoOutput.
|
inline |
|
inline |
|
inlinevirtualinherited |
Optional: returns the time (ms) spent in the last write() call.
Reimplemented in OutputTFT_eSPI, OutputTinyGPU, and OutputOpenCV.
|
inlinevirtualinherited |
True if the most recent write()+flush() call actually produced a displayable picture - default true, matching every synchronous decoder (H264Decoder, MJPEGDecoder, ...), which always decodes and pushes pixels fully within that one call. Override this only if your decoder can legitimately accept/decode a frame's bytes without emitting a picture during that same call - e.g. MPGDecoder, whose B-picture display-order reordering can hold a just-decoded picture back and instead emit an earlier one (or nothing at all) from a given write(), see its own override. Used by PacedVideoOutput to avoid counting/timing a call that did no real rendering work as a rendered frame - without this, its outputFPS()/frameCountI()/ frameCountP()/avgFrameMs() would overcount for such a decoder.
Reimplemented in MPGDecoder.
|
inlinevirtualinherited |
True if data (one complete encoded frame, as handed to write()) is a keyframe/sync-sample - self-contained, decodable without any earlier frame. Used e.g. by PacedVideoOutput to decide which frames are safe to drop, and whether it's safe to resume decoding after abandoning a backlog (see its own class comment). Default false: a plain VideoOutput doesn't know or care about codec structure - override this in a decoder for the bitstream format it actually parses (see H264Decoder/H264DecoderESP32S3's isH264KeyFrame()-based override, MPGDecoder's isMpeg1KeyFrame()- based one). Getting this right matters beyond bookkeeping: a target whose frames are never recognized as keyframes can leave a caller like PacedVideoOutput unable to ever resume after a resync.
Reimplemented in PacedVideoOutput, H264Decoder, H264DecoderESP32S3< Alloc >, MJPEGDecoder, MPGDecoder, and MultiVideoDecoder.
|
inlineoverridevirtual |
Hint to skip the expensive part of displaying the next frame(s) (e.g. the panel refresh) while still accepting and fully processing write() calls - used to recover from falling behind the playback schedule without breaking a codec's decode state (e.g. H.264 inter-prediction reference chain, which requires every frame to still be decoded even if it's never shown). Default no-op: implementations that can't skip rendering cheaply just ignore it and always render.
Reimplemented from VideoOutput.
|
inline |
|
inline |
|
inlineoverridevirtual |
Implements VideoOutput.
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |