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 |
◆ 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 |
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 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().
◆ 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: