H.264 video decoder: wraps TinyH264Decoder (https://github.com/pschatzmann/TinyH264) as a VideoOutput, so it can be plugged directly into e.g. DemuxerAVI::setOutputVideo()/ DemuxerMP4::setOutputVideo(). Consumes an Annex-B H.264 bitstream via write() and, once a complete picture has been decoded, writes it - converted to setVideoFormat()'s format (RGB565 by default, the common TFT wire format) - to the Print target configured via setOutput(), one write() call per decoded picture.
More...
#include <CodecH264.h>
|
| static void | onFrame (tinyh264::TinyH264Decoder< tinyh264::PSRAMAllocatorESP32< uint8_t > > &decoder, void *userData) |
| |
H.264 video decoder: wraps TinyH264Decoder (https://github.com/pschatzmann/TinyH264) as a VideoOutput, so it can be plugged directly into e.g. DemuxerAVI::setOutputVideo()/ DemuxerMP4::setOutputVideo(). Consumes an Annex-B H.264 bitstream via write() and, once a complete picture has been decoded, writes it - converted to setVideoFormat()'s format (RGB565 by default, the common TFT wire format) - to the Print target configured via setOutput(), one write() call per decoded picture.
write()/flush() implement the VideoOutput contract (see Video.h): write() may be called one or more times per frame - bytes are forwarded to the decoder immediately (Annex-B start codes are self-delimiting, so no internal buffering is needed here; a picture may complete partway through any write() call, not just at flush()). flush() is VideoOutput's no-op default - some producers (e.g. DemuxerAVI/DemuxerMP4) call it unconditionally after each frame, but this class has nothing to do with it.
Uses H264_DEFAULT_ALLOCATOR for the decoded picture buffers - see that macro's own comment above for the PSRAM-on-ESP32/heap- elsewhere default it picks, and how to override it.
- Author
- Phil Schatzmann
- Copyright
- GPLv3
◆ H264Decoder() [1/3]
◆ H264Decoder() [2/3]
◆ H264Decoder() [3/3]
◆ begin()
Reserves the decoder's picture buffers up front - see TinyH264Decoder::begin().
Implements VideoDecoder.
◆ codecFormat()
◆ driver()
| tinyh264::TinyH264Decoder< tinyh264::PSRAMAllocatorESP32< uint8_t > > & driver |
( |
| ) |
|
|
inline |
Direct access to the wrapped TinyH264Decoder, e.g. for its width()/ height()/y()/u()/v()/getY()/getU()/getV() accessors.
◆ end()
Releases the decoder's picture buffers - see TinyH264Decoder::end().
Implements VideoDecoder.
◆ flush()
◆ 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.
◆ hasError()
True if the most recent write() call ended in a bitstream error or hit an unsupported stream feature.
◆ isKeyFrame()
| bool isKeyFrame |
( |
const uint8_t * |
data, |
|
|
size_t |
len |
|
) |
| |
|
inlineoverridevirtual |
◆ isValid()
| bool isValid |
( |
const uint8_t * |
data, |
|
|
size_t |
len |
|
) |
| |
|
inlineoverridevirtual |
◆ onFrame()
| static void onFrame |
( |
tinyh264::TinyH264Decoder< tinyh264::PSRAMAllocatorESP32< uint8_t > > & |
decoder, |
|
|
void * |
userData |
|
) |
| |
|
inlinestaticprotected |
◆ setMaxRefFrames()
| void setMaxRefFrames |
( |
int |
n | ) |
|
|
inline |
Runtime-active maximum stored reference pictures - see TinyH264Decoder::setMaxRefFrames().
◆ setOutput() [1/2]
| void setOutput |
( |
Print & |
out | ) |
|
|
inlineoverridevirtual |
Defines the target the decoded picture is written to, one write() call per decoded picture, in the format selected via setVideoFormat() (RGB565 by default).
Implements VideoDecoder.
◆ setOutput() [2/2]
Defines the target each decoded picture is written to - the VideoOutput-specific counterpart of setOutput(Print&), for a target like OutputTinyGPU/OutputOpenCV that implements VideoOutput but not Print (the two are unrelated types - see VideoFrameMeter's own comment). Part of the base interface (unlike other decoder-specific extras) so code holding only a VideoDecoder& (e.g. VideoPlayer) can wire it to an arbitrary VideoOutput& without knowing the concrete decoder type - every current decoder already implemented this identically before it was pulled up into the interface.
Implements VideoDecoder.
◆ setSkipRender()
| virtual void setSkipRender |
( |
bool |
skip | ) |
|
|
inlinevirtualinherited |
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 in MultiVideoDecoder, OutputFPSMeter, OutputTinyGPU, PacedVideoOutput, and VideoFrameMeter.
◆ setVideoFormat()
Selects the pixel format written to setOutput()'s target - RGB565 (the default) is what most TFT display libraries expect; RGB666/ RGB888 for higher color depth displays; I420 to pass the decoded planes through unconverted (tightly packed: Y bytes, then U bytes, then V bytes, no row padding - see TinyH264Decoder::toYUV420()). Any other VideoFormat is logged and ignored (previous format kept).
Implements VideoDecoder.
◆ setVideoInfoSource()
◆ totalDecodeMs()
| uint64_t totalDecodeMs |
( |
| ) |
const |
|
inlineoverridevirtual |
Sum of time spent purely inside decoder_.write() (CAVLC decode + reconstruction) since begin() - excludes SD reads and demux overhead a caller's own outer timing bundles in alongside it, AND excludes the picture-ready callback's own cost (pixel-format conversion + pushing the result to setOutput()'s target, which decoder_.write() invokes synchronously mid-call - see writeToOutput()) - measured separately and subtracted in write(), so a caller comparing this against its own outer wall-clock time around write() (e.g. OutputFPSMeter) gets a real decode-vs-render split instead of a number that already secretly includes render.
Reimplemented from VideoOutput.
◆ videoInfo()
Reports the format/dimensions of the picture written to setOutput()'s target - format is setVideoFormat()'s most recently selected value (RGB565 if never called); width/height are the most recently decoded picture's (0 before any picture has been decoded).
Implements VideoDecoder.
◆ write()
| size_t write |
( |
const uint8_t * |
data, |
|
|
size_t |
len |
|
) |
| |
|
inlineoverridevirtual |
Feeds one chunk of Annex-B H.264 data - may be called more than once per frame (e.g. from a demuxer that hands over payload in pieces). Decodes immediately, invoking setOutput()'s Print once per completed picture from within this call (not deferred to flush()).
Implements VideoOutput.
◆ writeToOutput() [1/2]
◆ writeToOutput() [2/2]
| size_t writeToOutput |
( |
uint8_t * |
data, |
|
|
size_t |
len |
|
) |
| |
|
inlineprotected |
◆ decoder_
| tinyh264::TinyH264Decoder< tinyh264::PSRAMAllocatorESP32<uint8_t> > decoder_ |
|
protected |
◆ frame_buffer
◆ p_out
◆ p_out_video
◆ pixel_format
◆ total_decode_ms_
| uint64_t total_decode_ms_ = 0 |
|
protected |
◆ total_output_ms_
| uint32_t total_output_ms_ = 0 |
|
protected |
The documentation for this class was generated from the following file: