MPEG-1 (part 2) video decoder wrapper around TinyMPGDecoder.
More...
#include <CodecMPG.h>
|
| void | writeFrame (tinympg::TinyMPGDecoder< tinympg::PSRAMAllocatorESP32< uint8_t > > &decoder) |
| |
| size_t | writeToOutput (uint8_t *data, size_t len) |
| |
|
| static void | onFrame (tinympg::TinyMPGDecoder< tinympg::PSRAMAllocatorESP32< uint8_t > > &decoder, void *userData) |
| |
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
◆ MPGDecoder() [1/3]
◆ MPGDecoder() [2/3]
◆ MPGDecoder() [3/3]
◆ begin()
Initializes the decoder (allocates its picture buffers, etc).
Implements VideoDecoder.
◆ byteSwap()
◆ codecFormat()
◆ driver()
| tinympg::TinyMPGDecoder< tinympg::PSRAMAllocatorESP32< uint8_t > > & driver |
( |
| ) |
|
|
inline |
◆ end()
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.
◆ flush()
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.
◆ getWriteTimeMs()
| virtual uint32_t getWriteTimeMs |
( |
| ) |
const |
|
inlinevirtualinherited |
◆ hadOutput()
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.
◆ hasError()
◆ ignorePFrames()
| bool ignorePFrames |
( |
| ) |
const |
|
inline |
◆ isKeyFrame()
| bool isKeyFrame |
( |
const uint8_t * |
data, |
|
|
size_t |
len |
|
) |
| |
|
inlineoverridevirtual |
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.
◆ isValid()
| bool isValid |
( |
const uint8_t * |
data, |
|
|
size_t |
len |
|
) |
| |
|
inlineoverridevirtual |
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.
◆ onFrame()
| static void onFrame |
( |
tinympg::TinyMPGDecoder< tinympg::PSRAMAllocatorESP32< uint8_t > > & |
decoder, |
|
|
void * |
userData |
|
) |
| |
|
inlinestaticprotected |
◆ setByteSwap()
| void setByteSwap |
( |
bool |
active | ) |
|
|
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.
◆ setIgnorePFrames()
| void setIgnorePFrames |
( |
bool |
active | ) |
|
|
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.
◆ setOutput() [1/2]
| void setOutput |
( |
Print & |
out | ) |
|
|
inlineoverridevirtual |
Defines the target each decoded picture is written to.
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 - 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()
◆ totalDecodeMs()
| virtual uint64_t totalDecodeMs |
( |
| ) |
const |
|
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.
◆ videoInfo()
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 |
|
) |
| |
|
inlineoverridevirtual |
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.
◆ writeFrame()
| void writeFrame |
( |
tinympg::TinyMPGDecoder< tinympg::PSRAMAllocatorESP32< uint8_t > > & |
decoder | ) |
|
|
inlineprotected |
◆ writeToOutput()
| size_t writeToOutput |
( |
uint8_t * |
data, |
|
|
size_t |
len |
|
) |
| |
|
inlineprotected |
◆ byte_swap
◆ decoder_
| tinympg::TinyMPGDecoder< tinympg::PSRAMAllocatorESP32<uint8_t> > decoder_ |
|
protected |
◆ frame_buffer
◆ frame_emitted
| bool frame_emitted = false |
|
protected |
◆ p_out
◆ p_out_video
◆ pixel_format
The documentation for this class was generated from the following file: