|
arduino-audio-tools
|
MPEG-1 (part 2) video decoder wrapper around TinyMPGDecoder. More...
#include <CodecMPG.h>


Public Member Functions | |
| MPGDecoder () | |
| MPGDecoder (Print &out) | |
| MPGDecoder (VideoOutput &out) | |
| bool | begin () override |
| Initializes the decoder (allocates its picture buffers, etc). | |
| bool | byteSwap () const |
| VideoFormat | codecFormat () override |
| tinympg::TinyMPGDecoder< tinympg::PSRAMAllocatorESP32< uint8_t > > & | driver () |
| void | end () override |
| void | flush () override |
| virtual uint32_t | getWriteTimeMs () const |
| Optional: returns the time (ms) spent in the last write() call. | |
| bool | hadOutput () const override |
| bool | hasError () |
| bool | ignorePFrames () 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 | setIgnorePFrames (bool active) |
| void | setOutput (Print &out) override |
| Defines the target each decoded picture is written to. | |
| 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 | |
| void | writeFrame (tinympg::TinyMPGDecoder< tinympg::PSRAMAllocatorESP32< uint8_t > > &decoder) |
| size_t | writeToOutput (uint8_t *data, size_t len) |
Static Protected Member Functions | |
| static void | onFrame (tinympg::TinyMPGDecoder< tinympg::PSRAMAllocatorESP32< uint8_t > > &decoder, void *userData) |
Protected Attributes | |
| bool | byte_swap = true |
| tinympg::TinyMPGDecoder< tinympg::PSRAMAllocatorESP32< uint8_t > > | decoder_ |
| Vector< uint8_t > | frame_buffer |
| bool | frame_emitted = false |
| Print * | p_out = nullptr |
| VideoOutput * | p_out_video = nullptr |
| VideoFormat | pixel_format = VideoFormat::RGB565 |
MPEG-1 (part 2) video decoder wrapper around TinyMPGDecoder.
The class mirrors the usage style of CodecH264.h: feed MPEG-1 bitstream data via write(), and receive decoded frames on the configured output.
Note: Requires TinyMPG (TinyMPGDecoder.h) to be installed and reachable by the compiler include path: https://github.com/pschatzmann/TinyMPG
|
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.
|
inline |
|
inlineoverridevirtual |
Releases any picture still held back for display-order reordering (see TinyMPGDecoder's docs/decoding.md, "Frame delivery order and latency") before resetting the decoder - without this, the last anchor picture (or two, if the stream has B-pictures) of a session that ends here would never reach the frame callback at all, since write() below deliberately never triggers that release on its own (see its own comment).
Implements VideoDecoder.
|
inlineoverridevirtual |
Deliberately a no-op, not wired to TinyMPGDecoder in any way: this is called once per picture boundary by DemuxerMPG (ContainerMPG.h), not just at genuine end-of-stream, so treating it as "no more data is coming" (the way end() above does) would release every anchor picture the moment its own data finishes decoding instead of holding it back for correct B-picture reordering - that release only happens once end() runs, or once a genuine following picture's data arrives via write().
Reimplemented from VideoOutput.
|
inlinevirtualinherited |
Optional: returns the time (ms) spent in the last write() call.
Reimplemented in OutputTFT_eSPI, OutputTinyGPU, and OutputOpenCV.
|
inlineoverridevirtual |
See VideoOutput::hadOutput() - TinyMPGDecoder's B-picture display- order reordering means a given write() can decode a new picture without emitting it yet (held back), or emit an earlier held picture instead - either way "write()+flush() was called" doesn't reliably mean "a picture was just pushed to the output" the way it does for a synchronous decoder. Reflects whether writeFrame() (only ever invoked from TinyMPGDecoder's frame callback, i.e. only when a picture was actually ready) ran during the most recent write() call.
Reimplemented from VideoOutput.
|
inline |
|
inline |
See VideoOutput::isKeyFrame() - true only for an I-picture (picture_coding_type == 1); P- and B-pictures both depend on other frames, so neither counts as self-contained here.
Reimplemented from VideoOutput.
True if data contains an MPEG-1 sequence_header (00 00 01 B3) - required by spec to precede the first picture of any real MPEG-1 elementary stream, so it's reliably present in the very first access unit a demuxer ever hands to write() (bundled with the first GOP/ picture - see ContainerMPG.h's own unit-buffering comment). 0xB3 can never appear as a valid H.264 NAL header byte (forbidden_zero_bit would have to be 1), so this never false-positives on H.264 content. See VideoDecoder::isValid().
Reimplemented from VideoDecoder.
|
inlinestaticprotected |
|
inline |
Swaps the two bytes of every RGB565 pixel before it reaches setOutput()'s target - on by default. TinyMPGDecoder::toRGB565() (via convertYuv420ToRgb565(), TinyMPG/decoder/mpg_rgb.h) packs each pixel into a native uint16_t, which lands little-endian in memory on ESP32/most Arduino targets, but SPI TFT panels (ILI9341 etc.) expect RGB565 transmitted big-endian - without the swap, colors come out visibly wrong. Only affects VideoFormat::RGB565 - RGB666/RGB888/I420 are unaffected (already byte-oriented, not packed into a uint16_t). Turn off only if your VideoOutput target already performs its own byte-swap.
|
inline |
See tinympg::TinyMPGDecoder::setIgnorePFrames() - when set, P-pictures are silently discarded (no slices decoded, no callback fired, no error status) instead of being decoded; I- and B-pictures are unaffected. Off by default.
|
inlineoverridevirtual |
Defines the target each decoded picture is written to.
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 |
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.
|
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 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.
Forwards to TinyMPGDecoder::write() with the default isLastChunk=true ("this buffer is one whole, self-contained unit"). Correct because DemuxerMPG (ContainerMPG.h) now accumulates every fragment of a picture (across PES boundaries and its own small parse buffer) into one complete access unit before ever calling write() here - each call really does receive exactly one whole picture, never a boundary-split partial one. (Previously, before that buffering existed, DemuxerMPG forwarded video data in whatever increments happened to be buffered, and this needed isLastChunk=false to avoid TinyMPGDecoder treating a split unit as complete and silently reconstructing it from stale/wrong macroblocks - see ContainerMPG.h's own video_unit_buffer comment.)
Implements VideoOutput.
|
inlineprotected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |