arduino-audio-tools
Loading...
Searching...
No Matches
Public Member Functions | Public Attributes | Protected Member Functions | Static Protected Member Functions | Protected Attributes | Static Protected Attributes | List of all members

MPEG-1 System (Program) Stream Demuxer, as defined by ISO/IEC 11172-1: splits the pack_header/system_header/PES_packet framing apart and forwards the raw MPEG-1 video (ISO/IEC 11172-2) and MPEG-1 audio (ISO/IEC 11172-3, Layer I/II/III) elementary streams to setOutputVideo()/ setOutputAudio(). Both elementary streams are self-delimiting (the video ES has its own picture_start_code sequence, the audio ES its own frame sync word) so, like DemuxerAVI/DemuxerMP4, no separate decoding is done here - point the outputs at whatever decoder understands the codec (e.g. an MPEG1 video decoder, or an EncodedAudioStream wrapping an MP3/MP2 AudioDecoder). More...

#include <ContainerMPG.h>

Inheritance diagram for DemuxerMPG:
Demuxer ContainerDecoder MimeSource VideoInfoSource AudioDecoder AudioWriter AudioInfoSource AudioInfoSupport

Public Member Functions

 DemuxerMPG (int bufferSize=1024)
 
virtual void addNotifyAudioChange (AudioInfoSupport &bi)
 Adds target to be notified about audio changes.
 
AudioInfo audioInfo () override
 provides the actual input AudioInfo
 
virtual AudioInfo audioInfoOut ()
 
bool begin () override
 
virtual bool begin (AudioInfo info) override
 
virtual void clearNotifyAudioChange ()
 Deletes all change notify subscriptions.
 
void end () override
 
AudioInfoFormat getAudioInfo () override
 
PrintgetOutput ()
 
VideoInfo getVideoInfo () override
 
bool isNotifyActive ()
 Checks if the automatic AudioInfo update is active.
 
bool isValid (const uint8_t *data, size_t len) override
 
const char * mime () override
 
const char * mimeVideo () override
 Provides the container mime.
 
 operator bool () override
 
virtual bool removeNotifyAudioChange (AudioInfoSupport &bi)
 Removes a target in order not to be notified about audio changes.
 
void setAudioInfo (AudioInfo from) override
 for most decoders this is not needed
 
virtual bool setCodecConfig (const uint8_t *data, size_t len)
 Some decoders need e.g. a magic cookie to provide the relevant info for decoding.
 
void setNotifyActive (bool flag)
 Deactivate/Reactivate automatic AudioInfo updates: (default is active)
 
virtual void setOutput (AudioOutput &out_stream)
 Defines where the decoded result is written to.
 
virtual void setOutput (AudioStream &out_stream)
 Defines where the decoded result is written to.
 
void setOutput (Print &out) override
 
void setOutputAudio (Print &out) override
 
void setOutputVideo (Print &out) override
 
void setOutputVideo (VideoOutput &out) override
 
void setSendWavHeader (bool flag) override
 
VideoInfo videoInfo () override
 
size_t write (const uint8_t *data, size_t len) override
 

Public Attributes

int id
 custom id to be used by application
 

Protected Member Functions

void appendToAudio (const uint8_t *data, size_t len)
 Same as appendToVideo(), for audio_unit_buffer.
 
void appendToVideo (const uint8_t *data, size_t len)
 
bool continuePayload ()
 
void deliver (size_t len)
 
void deliverVideo (const uint8_t *data, size_t len)
 
void flushAudioUnit ()
 
void flushVideoUnit ()
 
long indexOfContainerStartCode (size_t from=0)
 
void notifyAudioChange (AudioInfo info)
 
bool parse ()
 
bool parsePack ()
 
bool parsePes (uint8_t id, bool isVideo)
 
bool parseSkip ()
 
bool parseSystemHeader ()
 
void probeAudioHeader (const uint8_t *data, size_t len)
 
void probeVideoHeader (const uint8_t *data, size_t len)
 
void writeBlocking (Print *out, uint8_t *data, size_t len)
 

Static Protected Member Functions

static bool isContainerLevelStartCode (uint8_t id)
 

Protected Attributes

uint8_t audio_channels = 0
 
bool audio_frame_open = false
 
bool audio_header_parsed = false
 
uint8_t audio_layer = 0
 0=not yet probed/reserved, else 1/2/3
 
Vector< uint8_t > audio_probe
 
uint32_t audio_sample_rate = 0
 
Vector< uint8_t > audio_unit_buffer
 
size_t audio_unit_len = 0
 
AudioInfo info
 
bool is_notify_active = true
 
bool is_parsing_active = true
 
bool is_skip_unit = false
 
bool is_video_unit = false
 
Vector< AudioInfoSupport * > notify_vector
 
Printp_output_audio = nullptr
 
Printp_output_video = nullptr
 
VideoOutputp_output_video_video = nullptr
 
Printp_print = nullptr
 
MPGParseBuffer parse_buffer
 
size_t remaining = 0
 
uint32_t total_bytes = 0
 
bool unbounded = false
 
bool unit_open = false
 
float video_fps = 0
 
bool video_frame_open = false
 
bool video_header_parsed = false
 
uint16_t video_height = 0
 
Vector< uint8_t > video_probe
 
Vector< uint8_t > video_unit_buffer
 
size_t video_unit_len = 0
 
bool video_unit_seen_picture = false
 
uint16_t video_width = 0
 

Static Protected Attributes

static const size_t VIDEO_PROBE_MAX = 64
 

Detailed Description

MPEG-1 System (Program) Stream Demuxer, as defined by ISO/IEC 11172-1: splits the pack_header/system_header/PES_packet framing apart and forwards the raw MPEG-1 video (ISO/IEC 11172-2) and MPEG-1 audio (ISO/IEC 11172-3, Layer I/II/III) elementary streams to setOutputVideo()/ setOutputAudio(). Both elementary streams are self-delimiting (the video ES has its own picture_start_code sequence, the audio ES its own frame sync word) so, like DemuxerAVI/DemuxerMP4, no separate decoding is done here - point the outputs at whatever decoder understands the codec (e.g. an MPEG1 video decoder, or an EncodedAudioStream wrapping an MP3/MP2 AudioDecoder).

Scope (v1): a single MPEG-1 video track (stream_id 0xE0) and a single MPEG-1 audio track (stream_id 0xC0) - the common case for files produced by encoders targeting this container (see MuxerMPG). Only the plain ISO/IEC 11172-1 pack_header (fixed 12 bytes, no stuffing) and PES header (PTS/DTS-or-none, no stuffing bytes, no STD_buffer field) are recognized; MPEG-2-style Program Streams (marker pattern '01' at the start of the pack header) are not supported.

The audio track is forwarded as a plain, continuous elementary-stream byte stream (PES packet boundaries are not required to line up with MP3/ MP2 frame boundaries - the decoder resyncs on its own frame sync word), so setOutputAudio() can point straight at an EncodedAudioStream wrapping any MPEG audio AudioDecoder (e.g. MP3DecoderHelix):

DemuxerMPG demuxer;
EncodedAudioStream audioOut(&i2s, &mp3); // MP3 -> PCM -> i2s
demuxer.setOutputAudio(audioOut);
demuxer.setOutputVideo(videoSink);
demuxer.begin();
// feed raw .mpg bytes:
demuxer.write(mpgData, len);
MPEG-1 System (Program) Stream Demuxer, as defined by ISO/IEC 11172-1: splits the pack_header/system_...
Definition ContainerMPG.h:111
void setOutputAudio(Print &out) override
Definition ContainerMPG.h:176
size_t write(const uint8_t *data, size_t len) override
Definition ContainerMPG.h:219
bool begin() override
Definition ContainerMPG.h:138
void setOutputVideo(Print &out) override
Definition ContainerMPG.h:186
A more natural Stream class to process encoded data (aac, wav, mp3...) which also supports the decodi...
Definition AudioEncoded.h:282
MP3 Decoder using libhelix: https://github.com/pschatzmann/arduino-libhelix This is basically just a ...
Definition CodecMP3Helix.h:20
Author
Phil Schatzmann

Constructor & Destructor Documentation

◆ DemuxerMPG()

DemuxerMPG ( int  bufferSize = 1024)
inline
Parameters
bufferSizeinternal parse buffer size - must be able to hold at least one full pack_header/system_header/PES header (a few dozen bytes)

Member Function Documentation

◆ addNotifyAudioChange()

virtual void addNotifyAudioChange ( AudioInfoSupport bi)
inlinevirtualinherited

◆ appendToAudio()

void appendToAudio ( const uint8_t *  data,
size_t  len 
)
inlineprotected

Same as appendToVideo(), for audio_unit_buffer.

◆ appendToVideo()

void appendToVideo ( const uint8_t *  data,
size_t  len 
)
inlineprotected

Appends to video_unit_buffer with amortized (doubling) growth - see its comment for why an exact-size resize() per call would be O(N^2).

◆ audioInfo()

AudioInfo audioInfo ( )
inlineoverridevirtualinherited

◆ audioInfoOut()

virtual AudioInfo audioInfoOut ( )
inlinevirtualinherited

◆ begin() [1/2]

bool begin ( )
inlineoverridevirtual

Reimplemented from AudioDecoder.

◆ begin() [2/2]

virtual bool begin ( AudioInfo  info)
inlineoverridevirtualinherited

Reimplemented from AudioWriter.

Reimplemented in DecoderBasic, and OggContainerDecoder.

◆ clearNotifyAudioChange()

virtual void clearNotifyAudioChange ( )
inlinevirtualinherited

Deletes all change notify subscriptions.

Reimplemented in RTSPClient< TcpClient, UdpSocket >.

◆ continuePayload()

bool continuePayload ( )
inlineprotected

◆ deliver()

void deliver ( size_t  len)
inlineprotected

Appends one delivered fragment to the appropriate access-unit accumulator instead of writing it straight through - see video_unit_buffer's comment. The unit is only actually written once it's complete, from flushVideoUnit()/flushAudioUnit().

◆ deliverVideo()

void deliverVideo ( const uint8_t *  data,
size_t  len 
)
inlineprotected

Appends video bytes to video_unit_buffer, splitting off a new access unit whenever an internal picture_start_code (00 00 01 00) marks the start of a NEW picture - needed because flushVideoUnit()'s other caller (see parsePes()) only flushes when a new video PES arrives with a PTS, which some encoders don't set on every single picture's PES packet (e.g. only once per GOP) - relying on that alone can silently bundle many pictures (an entire GOP, in the worst case) into one access unit, which then reaches the decoder as one huge, multi-picture write() call instead of one call per picture (breaking every caller downstream that assumes that 1:1 correspondence, e.g. PacedVideoOutput's per-frame scheduling/counting).

The first picture_start_code seen in a fresh unit is never a split point (it stays attached to any preceding sequence_header/ GOP_header, matching what flushVideoUnit()'s own doc comment already assumes) - only the second and later ones are. video_unit_seen_picture tracks whether the current (not yet flushed) unit has seen its first one yet; reset to false by flushVideoUnit() itself once a unit is actually emptied, and re-set to true here immediately after an internal split (the retained remainder already starts with one).

◆ end()

void end ( )
inlineoverridevirtual

Reimplemented from AudioDecoder.

◆ flushAudioUnit()

void flushAudioUnit ( )
inlineprotected

Writes out audio_unit_buffer as one single, complete write() call if it currently holds anything, then resets it for the next unit.

◆ flushVideoUnit()

void flushVideoUnit ( )
inlineprotected

Writes out video_unit_buffer as one single, complete write() call if it currently holds anything, then resets it for the next unit. Call once a picture is known to be complete (a new video PES with a PTS starts, an internal picture_start_code marks a new one - see deliverVideo() - or the stream/end() is closing) - never mid-picture.

◆ getAudioInfo()

AudioInfoFormat getAudioInfo ( )
inlineoverridevirtual

Common audio info, parsed from the audio ES's own MPEG audio frame header once seen - falls back to 44100/stereo if not yet available.

Implements Demuxer.

◆ getOutput()

Print * getOutput ( )
inlineinherited

◆ getVideoInfo()

VideoInfo getVideoInfo ( )
inlineoverridevirtual

Common video info (width/height/fps/format), parsed from the video ES's own sequence_header (ISO/IEC 11172-2) once seen - all zero/ VideoFormat::MPEG1 until then.

Implements Demuxer.

◆ indexOfContainerStartCode()

long indexOfContainerStartCode ( size_t  from = 0)
inlineprotected

Like parse_buffer.indexOfStartCode(), but skips past any start code that isn't a genuine container-level boundary (see isContainerLevelStartCode()) - needed for unbounded video PES payloads (PES_packet_length==0, ISO/IEC 11172-1's convention for a video access unit whose length isn't known up front): the payload is only terminated by the next container-level unit, per spec, but it's also full of the video ES's own internal start codes (picture/slice/sequence/GOP) that plain indexOfStartCode() can't tell apart from that - mistaking one for the payload's end would drop it into the "reserved/unrecognized id" fallback in parse(), silently corrupting the video ES one byte at a time from there.

◆ isContainerLevelStartCode()

static bool isContainerLevelStartCode ( uint8_t  id)
inlinestaticprotected

True if 'id' (the byte after a 00 00 01 start-code prefix) marks a genuine container-level unit boundary (a new pack_header/ system_header/program_end/program_stream_map/private or padding stream/audio or video PES) rather than something internal to the video ES itself (a picture_start_code, a slice, or a sequence_header/ GOP/extension/user_data code - ISO/IEC 11172-2's own 0x00-0xB8 range). See indexOfContainerStartCode().

◆ isNotifyActive()

bool isNotifyActive ( )
inlineinherited

Checks if the automatic AudioInfo update is active.

◆ isValid()

bool isValid ( const uint8_t *  data,
size_t  len 
)
inlineoverridevirtual

True if data starts with an MPEG Program Stream pack_start_code (00 00 01 BA) - see Demuxer::isValid().

Reimplemented from Demuxer.

◆ mime()

const char * mime ( )
inlineoverridevirtual

Provides the audio mime - "audio/mpeg" covers MPEG-1 Layer I/II/III alike (there's no separately registered "audio/mp2"), but once the audio ES's own frame header has been probed (see probeAudioHeader()) a Layer II stream - the common case for this container, and what MuxerMPG itself produces - gets an explicit RFC 6381 codecs parameter naming the layer. Layer I/III/not-yet-probed still report the plain generic mime.

Implements Demuxer.

◆ mimeVideo()

const char * mimeVideo ( )
inlineoverridevirtual

Provides the container mime.

Implements Demuxer.

◆ notifyAudioChange()

void notifyAudioChange ( AudioInfo  info)
inlineprotectedinherited

◆ operator bool()

operator bool ( )
inlineoverridevirtual

Implements AudioWriter.

◆ parse()

bool parse ( )
inlineprotected

Parses/consumes as much as is currently buffered; returns true if progress was made (call again - more units may already be buffered), false if it needs more data (wait for the next write()).

◆ parsePack()

bool parsePack ( )
inlineprotected

◆ parsePes()

bool parsePes ( uint8_t  id,
bool  isVideo 
)
inlineprotected

◆ parseSkip()

bool parseSkip ( )
inlineprotected

program_stream_map / private_stream_1 / padding_stream / private_stream_2: same PES_packet_length-prefixed framing, payload discarded.

◆ parseSystemHeader()

bool parseSystemHeader ( )
inlineprotected

◆ probeAudioHeader()

void probeAudioHeader ( const uint8_t *  data,
size_t  len 
)
inlineprotected

Inspects the first 4 bytes of the audio ES for an MPEG audio frame header (ISO/IEC 11172-3) to determine sample_rate/channels.

◆ probeVideoHeader()

void probeVideoHeader ( const uint8_t *  data,
size_t  len 
)
inlineprotected

Accumulates the first bytes of the video ES looking for its sequence_header (00 00 01 B3) to determine width/height/fps - harmless to keep calling once found, since video_header_parsed then short-circuits it.

◆ removeNotifyAudioChange()

virtual bool removeNotifyAudioChange ( AudioInfoSupport bi)
inlinevirtualinherited

Removes a target in order not to be notified about audio changes.

Reimplemented in RTSPClient< TcpClient, UdpSocket >.

◆ setAudioInfo()

void setAudioInfo ( AudioInfo  from)
inlineoverridevirtualinherited

for most decoders this is not needed

Implements AudioWriter.

Reimplemented in DecoderALAC, CodecChain, DSFDecoder, DecoderL8, OpusAudioDecoder, OpusMultiStreamAudioDecoder, CodecNOP, G729Decoder, and G7xxDecoder.

◆ setCodecConfig()

virtual bool setCodecConfig ( const uint8_t *  data,
size_t  len 
)
inlinevirtualinherited

Some decoders need e.g. a magic cookie to provide the relevant info for decoding.

Reimplemented in DecoderALAC, and MultiDecoder.

◆ setNotifyActive()

void setNotifyActive ( bool  flag)
inlineinherited

Deactivate/Reactivate automatic AudioInfo updates: (default is active)

◆ setOutput() [1/3]

virtual void setOutput ( AudioOutput out_stream)
inlinevirtualinherited

Defines where the decoded result is written to.

Reimplemented in ADTSDecoder, CodecChain, MTSDecoder, MTSDecoderTSDemux, and MetaDataFilterDecoder.

◆ setOutput() [2/3]

virtual void setOutput ( AudioStream out_stream)
inlinevirtualinherited

Defines where the decoded result is written to.

Reimplemented in ADTSDecoder, CodecChain, MTSDecoder, MTSDecoderTSDemux, and MetaDataFilterDecoder.

◆ setOutput() [3/3]

void setOutput ( Print out)
inlineoverridevirtual

Satisfies the AudioWriter/AudioDecoder interface - needed so EncodedAudioOutput/EncodedAudioStream's polymorphic AudioDecoder* wiring reaches the audio output correctly; delegates to setOutputAudio().

Reimplemented from AudioDecoder.

◆ setOutputAudio()

void setOutputAudio ( Print out)
inlineoverridevirtual

Defines the audio output stream - e.g. an EncodedAudioStream wrapping an MP3/MP2 AudioDecoder, or any other Print if you want the raw payload as-is.

Implements Demuxer.

◆ setOutputVideo() [1/2]

void setOutputVideo ( Print out)
inlineoverridevirtual

Defines the video output - e.g. a VideoOutput implementation, or any other Print if you want the raw MPEG-1 video ES as-is.

Implements Demuxer.

◆ setOutputVideo() [2/2]

void setOutputVideo ( VideoOutput out)
inlineoverridevirtual

Defines the video output - the VideoOutput-specific counterpart of setOutputVideo(Print&), for a target like PacedVideoOutput/ 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 concrete-class-specific extras) so code holding only a Demuxer& (e.g. VideoPlayer) can wire it to an arbitrary VideoOutput& without knowing the concrete container format - every current demuxer already implemented this identically before it was pulled up into the interface.

Implements Demuxer.

◆ setSendWavHeader()

void setSendWavHeader ( bool  flag)
inlineoverridevirtual

Not applicable: MPEG-1 audio (Layer I/II/III) is compressed and self-framed (its own sync word), unlike PCM - it never needs a synthetic WAV header. Provided only to satisfy the Demuxer interface.

Implements Demuxer.

◆ videoInfo()

VideoInfo videoInfo ( )
inlineoverridevirtualinherited

Fulfills VideoInfoSource::videoInfo(), so any Demuxer can be passed directly to e.g. OutputOpenCV::setVideoInfoSource() - note the reported 'format' is the container's codec (e.g. H264), not necessarily what ends up written to a raw-picture VideoOutput/Print (that depends on whatever decoder sits between the demuxer and the output); consumers that care about the decoded format should still set it explicitly and rely on this only for width/height.

Implements VideoInfoSource.

◆ write()

size_t write ( const uint8_t *  data,
size_t  len 
)
inlineoverridevirtual

Implements AudioWriter.

◆ writeBlocking()

void writeBlocking ( Print out,
uint8_t *  data,
size_t  len 
)
inlineprotectedinherited

Member Data Documentation

◆ audio_channels

uint8_t audio_channels = 0
protected

◆ audio_frame_open

bool audio_frame_open = false
protected

◆ audio_header_parsed

bool audio_header_parsed = false
protected

◆ audio_layer

uint8_t audio_layer = 0
protected

0=not yet probed/reserved, else 1/2/3

◆ audio_probe

Vector<uint8_t> audio_probe
protected

◆ audio_sample_rate

uint32_t audio_sample_rate = 0
protected

◆ audio_unit_buffer

Vector<uint8_t> audio_unit_buffer
protected

◆ audio_unit_len

size_t audio_unit_len = 0
protected

◆ id

int id
inherited

custom id to be used by application

◆ info

AudioInfo info
protectedinherited

◆ is_notify_active

bool is_notify_active = true
protectedinherited

◆ is_parsing_active

bool is_parsing_active = true
protected

◆ is_skip_unit

bool is_skip_unit = false
protected

◆ is_video_unit

bool is_video_unit = false
protected

◆ notify_vector

Vector<AudioInfoSupport*> notify_vector
protectedinherited

◆ p_output_audio

Print* p_output_audio = nullptr
protected

◆ p_output_video

Print* p_output_video = nullptr
protected

◆ p_output_video_video

VideoOutput* p_output_video_video = nullptr
protected

◆ p_print

Print* p_print = nullptr
protectedinherited

◆ parse_buffer

MPGParseBuffer parse_buffer
protected

◆ remaining

size_t remaining = 0
protected

◆ total_bytes

uint32_t total_bytes = 0
protected

◆ unbounded

bool unbounded = false
protected

◆ unit_open

bool unit_open = false
protected

◆ video_fps

float video_fps = 0
protected

◆ video_frame_open

bool video_frame_open = false
protected

◆ video_header_parsed

bool video_header_parsed = false
protected

◆ video_height

uint16_t video_height = 0
protected

◆ video_probe

Vector<uint8_t> video_probe
protected

◆ VIDEO_PROBE_MAX

const size_t VIDEO_PROBE_MAX = 64
staticprotected

◆ video_unit_buffer

Vector<uint8_t> video_unit_buffer
protected

◆ video_unit_len

size_t video_unit_len = 0
protected

◆ video_unit_seen_picture

bool video_unit_seen_picture = false
protected

◆ video_width

uint16_t video_width = 0
protected

The documentation for this class was generated from the following file: