|
arduino-audio-tools
|
Motion-JPEG video decoder: wraps TinyJPEGDecoder (https://github.com/pschatzmann/TinyJPEG, a header-only port of ChaN's TJpgDec) as a VideoDecoder, so it can be plugged directly into e.g. DemuxerAVI::setOutputVideo()/DemuxerMP4::setOutputVideo() - the same role H264Decoder (CodecH264.h) and MPGDecoder (CodecMPG.h) play for their own codecs. Named "MJPEGDecoder" rather than reusing TinyJPEGDecoder's own name to avoid shadowing that class from within this one. More...
#include <CodecJPEG.h>
Public Member Functions | |
| MJPEGDecoder () | |
| MJPEGDecoder (Print &out) | |
| MJPEGDecoder (VideoOutput &out) | |
| bool | begin () override |
| Initializes the decoder (allocates its picture buffers, etc). | |
| bool | byteSwap () const |
| VideoFormat | codecFormat () override |
| void | end () override |
| Releases the decoder's resources. | |
| void | flush () override |
| virtual uint32_t | getWriteTimeMs () const |
| Optional: returns the time (ms) spent in the last write() call. | |
| virtual bool | hadOutput () const |
| bool | isKeyFrame (const uint8_t *data, size_t len) override |
| bool | isValid (const uint8_t *data, size_t len) override |
| void | setByteSwap (bool active) |
| void | setOutput (Print &out) override |
| void | setOutput (VideoOutput &out) override |
| virtual void | setSkipRender (bool skip) |
| void | setVideoFormat (VideoFormat format) override |
| virtual void | setVideoInfoSource (VideoInfoSource &source) |
| virtual uint64_t | totalDecodeMs () const |
| VideoInfo | videoInfo () override |
| size_t | write (const uint8_t *data, size_t len) override |
Protected Member Functions | |
| bool | writeBlock (int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *data) |
| size_t | writeToOutput (const uint8_t *data, size_t len) |
Static Protected Member Functions | |
| static bool | onBlock (tinyjpeg::TinyJPEGDecoder &decoder, int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *data) |
Protected Attributes | |
| bool | byte_swap = true |
| tinyjpeg::TinyJPEGDecoder | decoder_ |
| Vector< uint8_t > | frame_buffer |
| uint16_t | height_ = 0 |
| Vector< uint8_t > | img_vector |
| Print * | p_out = nullptr |
| VideoOutput * | p_out_video = nullptr |
| size_t | pos = 0 |
| uint64_t | start_ms = 0 |
| uint16_t | width_ = 0 |
Motion-JPEG video decoder: wraps TinyJPEGDecoder (https://github.com/pschatzmann/TinyJPEG, a header-only port of ChaN's TJpgDec) as a VideoDecoder, so it can be plugged directly into e.g. DemuxerAVI::setOutputVideo()/DemuxerMP4::setOutputVideo() - the same role H264Decoder (CodecH264.h) and MPGDecoder (CodecMPG.h) play for their own codecs. Named "MJPEGDecoder" rather than reusing TinyJPEGDecoder's own name to avoid shadowing that class from within this one.
write()/flush() implement the VideoOutput contract (see Video.h), but unlike H264Decoder/MPGDecoder - which decode incrementally as Annex-B/ PES bytes arrive, with no separate "frame complete" signal needed - a bare JPEG byte stream has no equivalent self-framing a demuxer can use to decode early. write() therefore just accumulates one JPEG image's bytes, and flush() (called by e.g. DemuxerAVI/DemuxerMP4 at each frame boundary) decodes the assembled image directly into a full-frame RGB565 buffer and writes it to the target configured via setOutput(), one write() call per decoded picture - same convention as H264Decoder/ MPGDecoder, so any VideoOutput (OutputTFT_eSPI, OutputTinyGPU, OutputOpenCV, ...) works unchanged regardless of which codec produced the picture.
Owns a plain, private tinyjpeg::TinyJPEGDecoder member - unlike Bodmer's JPEGDecoder (this class's previous backend), TinyJPEGDecoder threads its per-decode context through the decoder's own instance instead of a global singleton, so multiple MJPEGDecoder instances (or any other concurrent TinyJPEGDecoder use elsewhere in the same sketch) coexist safely.
|
inline |
|
inline |
|
inline |
|
inlineoverridevirtual |
Initializes the decoder (allocates its picture buffers, etc).
Implements VideoDecoder.
|
inline |
|
inlineoverridevirtual |
The compressed bitstream codec this decoder consumes (e.g. VideoFormat::H264, VideoFormat::MJPEG) - NOT the same axis as setVideoFormat()/videoInfo().format below, which is the decoded pixel format this decoder produces. Used by MultiVideoDecoder::addDecoder() to register a decoder under its own codec instead of the caller having to pass it separately (and possibly get it wrong).
Implements VideoDecoder.
|
inlineoverridevirtual |
Releases the decoder's resources.
Implements VideoDecoder.
|
inlineoverridevirtual |
Decodes the assembled JPEG image and writes the resulting RGB565 frame to setOutput()'s target, then resets for the next frame - a no-op if write() hasn't accumulated anything since the last call. Reads the picture's width/height first (getJpgSize() - a cheap, header-only parse) so frame_buffer can be sized before the per-MCU-block callback (onBlock()/writeBlock()) starts firing, since TinyJPEGDecoder streams blocks out via callback as it decodes rather than handing back a whole decoded picture at once.
Reimplemented from VideoOutput.
|
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.
|
inlineoverridevirtual |
See VideoOutput::isKeyFrame() - always true: Motion-JPEG is an all-intra format, every frame is a complete, independently decodable image with no inter-frame prediction (the same property that makes an H.264 IDR frame or an MPEG-1 I-picture "key", just true of every frame here instead of periodically). This matters beyond classification - PacedVideoOutput's awaiting_keyframe recovery latch (set after a resync) only clears once a frame reports isKeyFrame()==true; returning false here would leave every frame classified as non-key, so once any resync ever fired, that latch would never clear and rendering would silently stall forever.
Reimplemented from VideoOutput.
|
inlineoverridevirtual |
True if data looks like the start of a JPEG image (SOI marker FF D8) - unambiguous, and reliable even on the very first write() of a stream since a JPEG image always begins at FF D8 regardless of framing - see VideoDecoder::isValid().
Reimplemented from VideoDecoder.
|
inlinestaticprotected |
Per-MCU-block callback registered on decoder_ - see tinyjpeg::SketchCallback. decoder's getUserData() is this instance (set in the constructor), routing back to writeBlock().
|
inline |
Swaps the two bytes of every decoded RGB565 pixel before it reaches setOutput()'s target - on by default. TinyJPEGDecoder packs each pixel in the CPU's native uint16_t byte order (little-endian on ESP32/most Arduino targets) unless told otherwise, but SPI TFT panels (ILI9341 etc.) expect RGB565 transmitted big-endian - without the swap, colors come out visibly wrong (channels scrambled, not just a hue shift). Forwards straight to tinyjpeg::TinyJPEGDecoder::setSwapBytes(). Turn off only if your VideoOutput target already performs its own byte-swap (e.g. some display libraries' pushColors() variants).
|
inlineoverridevirtual |
Defines the target the decoded picture is written to, one write() call per decoded picture (RGB565 - the only format TinyJPEGDecoder produces).
Implements VideoDecoder.
|
inlineoverridevirtual |
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.
|
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.
|
inlineoverridevirtual |
TinyJPEGDecoder only ever produces RGB565 - any other value is logged and ignored.
Implements VideoDecoder.
|
inlinevirtualinherited |
Optional: registers where width/height/fps/format (VideoInfo) come from - e.g. the demuxer feeding this output, so it can size its own buffers/panel setup without the caller having to duplicate that call per sketch (VideoPlayer::begin() does this automatically for whichever VideoOutput it was given). Default no-op: only implementations that actually need VideoInfo (OutputTinyGPU/ OutputOpenCV/OutputTFT_eSPI) override this.
Reimplemented in MultiVideoDecoder, OutputOpenCV, OutputTFT_eSPI, and OutputTinyGPU.
|
inlinevirtualinherited |
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 in H264Decoder, and MultiVideoDecoder.
|
inlineoverridevirtual |
Reports the dimensions of the most recently decoded picture - 0 before any picture has been decoded.
Implements VideoDecoder.
|
inlineoverridevirtual |
Accumulates one JPEG image's bytes - may be called more than once per frame (e.g. from a demuxer that hands over payload in pieces). Decoding happens on flush(), not here.
Implements VideoOutput.
|
inlineprotected |
Copies one decoded MCU block into frame_buffer at (x, y) - a right/bottom edge block can be narrower/shorter than a full MCU (w/h already reflect that; TinyJPEGDecoder, unlike the old JPEGDecoder backend, never hands back an over-wide/over-tall edge block in the first place), so no separate clamping is needed beyond the defensive min() below.
|
inlineprotected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |