MultiVideoDecoder pre-registered with every video codec this library ships a portable (no hardware-specific backend) software decoder for: MJPEGDecoder (Motion-JPEG, TinyJPEG, CodecJPEG.h), MPGDecoder (MPEG-1, TinyMPG, CodecMPG.h), H264Decoder (H.264 Annex-B, TinyH264, CodecH264.h) - drop it into a demuxer's setOutputVideo() the same way any single decoder would go, and it self-selects the right one from the bitstream's own framing instead of the caller having to know the codec up front. Use the plain MultiVideoDecoder (MultiVideoDecoder.h) instead if you don't want all three codec libraries pulled in unconditionally - register only what your content actually needs via its own addDecoder().
More...
#include <MultiVideoDecoderFull.h>
MultiVideoDecoder pre-registered with every video codec this library ships a portable (no hardware-specific backend) software decoder for: MJPEGDecoder (Motion-JPEG, TinyJPEG, CodecJPEG.h), MPGDecoder (MPEG-1, TinyMPG, CodecMPG.h), H264Decoder (H.264 Annex-B, TinyH264, CodecH264.h) - drop it into a demuxer's setOutputVideo() the same way any single decoder would go, and it self-selects the right one from the bitstream's own framing instead of the caller having to know the codec up front. Use the plain MultiVideoDecoder (MultiVideoDecoder.h) instead if you don't want all three codec libraries pulled in unconditionally - register only what your content actually needs via its own addDecoder().
Dependencies (install via Library Manager) - all three are required to build this header, regardless of which formats your content actually uses:
- Author
- Phil Schatzmann
- Copyright
- GPLv3
◆ MultiVideoDecoderFull()
◆ addDecoder()
Registers a decoder under its own VideoDecoder::codecFormat() - see the class comment for when/how it's later selected (VideoInfoSource match, or its own VideoDecoder::isValid() as a content-sniffing fallback). Call before the first write() reaches this object.
Replaces, rather than adds to, any decoder already registered for that format - at most one entry per format, so e.g. registering H264DecoderESP32S3 (codecFormat() == H264) actually overrides a previously-registered H264Decoder instead of silently losing to it: both write()'s VideoInfoSource-format lookup and its isValid() fallback loop match the first entry found for a format, so a stale second entry would otherwise be permanently unreachable dead weight, never actually selected.
◆ begin()
|
|
inlineoverridevirtualinherited |
◆ codecFormat()
|
|
inlineoverridevirtualinherited |
◆ end()
|
|
inlineoverridevirtualinherited |
◆ ensureSelected()
| void ensureSelected |
( |
const uint8_t * |
data, |
|
|
size_t |
len |
|
) |
| |
|
inlineprotectedinherited |
Runs detection (VideoInfoSource match, else each decoder's own isValid() as a content-sniffing fallback - see the class comment) exactly once, off whichever data/len it's first called with - shared by write() and isKeyFrame() so either one can trigger it (see isKeyFrame()'s own comment for why that matters). A no-op on every call after the first.
◆ flush()
|
|
inlineoverridevirtualinherited |
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.
◆ getWriteTimeMs()
| virtual uint32_t getWriteTimeMs |
( |
| ) |
const |
|
inlinevirtualinherited |
◆ hadOutput()
| virtual bool hadOutput |
( |
| ) |
const |
|
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.
◆ isKeyFrame()
| bool isKeyFrame |
( |
const uint8_t * |
data, |
|
|
size_t |
len |
|
) |
| |
|
inlineoverridevirtualinherited |
Also triggers detection (see ensureSelected()) if it hasn't run yet - a caller upstream of write() (e.g. PacedVideoOutput::write(), which checks isKeyFrame() before deciding whether to even queue/forward a frame - see its own setIgnorePFrames()) can otherwise call this first, on the very same bytes write() would have detected from, and get a permanent false: no decoder ever selected (since write() never runs on a frame classified "drop"), so isKeyFrame() never returns true either - a deadlock. Detecting here too, off the exact same data/len write() would have used, closes that gap.
Reimplemented from VideoOutput.
◆ isValid()
| virtual bool isValid |
( |
const uint8_t * |
data, |
|
|
size_t |
len |
|
) |
| |
|
inlinevirtualinherited |
True if data (the start of an access unit, as handed to write()) looks like this decoder's own bitstream format - content-sniffing, not a guarantee (see the concrete class for exactly what's checked). Used by MultiVideoDecoder to auto-select a registered decoder when no VideoInfoSource answer is available (see its own class comment); not otherwise part of the write()/flush() decode path. Default false, matching VideoOutput::isKeyFrame()'s own default - a decoder not meant to be auto-detected this way (e.g. a hardware-accelerated backend not registered by default, still usable via an explicit VideoInfoSource-based selection) simply never overrides it.
Reimplemented in H264Decoder, MJPEGDecoder, and MPGDecoder.
◆ select()
◆ selectedFormat()
◆ setOutput() [1/2]
| void setOutput |
( |
Print & |
out | ) |
|
|
inlineoverridevirtualinherited |
Defines the target each decoded picture is written to.
Implements VideoDecoder.
◆ setOutput() [2/2]
|
|
inlineoverridevirtualinherited |
◆ setSkipRender()
| void setSkipRender |
( |
bool |
skip | ) |
|
|
inlineoverridevirtualinherited |
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.
◆ setVideoFormat()
|
|
inlineoverridevirtualinherited |
Selects the pixel format written to setOutput()'s target - e.g. VideoFormat::RGB565 (the common TFT wire format), RGB666/RGB888 for higher color depth displays, or I420 to pass the decoded planes through unconverted. Not every decoder backend supports every value (e.g. RGB666/RGB888 are TinyH264-only, not available on the esp_h264 backend) - unsupported values are logged and ignored (the previously selected format stays in effect); see the concrete class for exactly which ones it supports. Call before begin().
Implements VideoDecoder.
◆ setVideoInfoSource()
Provides the container's own answer for which codec the video track actually is - takes precedence over content-sniffing when set (see the class comment). Pass the demuxer feeding this object, e.g. multiVideoDecoder.setVideoInfoSource(aviDemuxer). Must outlive this object; call before the first write().
Reimplemented from VideoOutput.
◆ totalDecodeMs()
| uint64_t totalDecodeMs |
( |
| ) |
const |
|
inlineoverridevirtualinherited |
Optional: sum of time (ms) spent purely decoding (excluding any surrounding convert/render/SPI work a subclass's write() also does) since begin() - see H264Decoder's own override for the only current implementation. Default 0: only meaningful for a decoder that separates decode time from render time internally: PacedVideoOutput:: logTo() prints a decode-vs-render split under "avg decode ms:" only when this returns nonzero.
Reimplemented from VideoOutput.
◆ videoInfo()
|
|
inlineoverridevirtualinherited |
Reports the format/dimensions of the picture written to setOutput()'s target - VideoInfo::format is always the format most recently selected via setVideoFormat() (RGB565 if never called), the reliable way to determine it (rather than assuming); width/ height reflect the most recently decoded picture, 0 before any picture has been decoded.
Implements VideoDecoder.
◆ write()
| size_t write |
( |
const uint8_t * |
data, |
|
|
size_t |
len |
|
) |
| |
|
inlineoverridevirtualinherited |
◆ decoders
◆ h264
◆ is_first
◆ mjpeg
◆ mpeg1
◆ p_selected
◆ p_selected_format
◆ p_video_info_source
The documentation for this class was generated from the following file: