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

DemuxerMP4 extracts both the audio and (H.264) video track from a general, interleaved MP4/ISO-BMFF stream - unlike M4AAudioDemuxer/ M4AAudioFileDemuxer, which only handle a single (audio) track. More...

#include <ContainerMP4.h>

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

Classes

struct  StscEntry
 sample-to-chunk table entry (stsc) More...
 
struct  SttsEntry
 
struct  Track
 One track (audio or video) as found in 'moov'. More...
 

Public Types

using Codec = M4ACommonDemuxer::Codec
 

Public Member Functions

 DemuxerMP4 ()
 
 DemuxerMP4 (Print &video_out, Print &audio_out)
 
 DemuxerMP4 (SeekableSource &seekSource)
 
 DemuxerMP4 (SpoolStorageFactory &spoolFactory)
 
 DemuxerMP4 (VideoOutput &video_out, Print &audio_out)
 
 ~DemuxerMP4 ()
 
virtual void addNotifyAudioChange (AudioInfoSupport &bi)
 Adds target to be notified about audio changes.
 
Vector< uint8_t > & audioALACMagicCookie ()
 
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
 
bool quickStart ()
 
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 setSeekSource (SeekableSource &seekSource)
 
void setSpoolStorageFactory (SpoolStorageFactory &spoolFactory)
 
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 advanceChunkIfNeeded ()
 
bool beginBoxAccum (const MP4Parser::Box &box)
 
uint64_t boxPayloadFileOffset ()
 
void configureSpoolStores (Track &t)
 
void dispatchAudio (Track &t, const uint8_t *data, size_t size, bool isFirst)
 
void dispatchSample (Track &t, const uint8_t *data, size_t size, bool isFirst)
 
void dispatchVideo (Track &t, const uint8_t *data, size_t size, bool isFirst)
 
void endBoxAccum ()
 Call once a box_accum-using handler has fully processed a complete box.
 
void feed (const uint8_t *data, size_t len)
 
void flushVideo ()
 
void freeTracks ()
 
void notifyAudioChange (AudioInfo info)
 
void onAc3 (const MP4Parser::Box &box)
 
void onAlac (const MP4Parser::Box &box)
 
void onAvc1 (const MP4Parser::Box &box)
 
void onAvcC (const MP4Parser::Box &box)
 
void onEsds (const MP4Parser::Box &box)
 
void onHdlr (MP4Parser::Box &box)
 
void onHevc (const MP4Parser::Box &box)
 
void onMdat (MP4Parser::Box &box)
 
void onMdhd (MP4Parser::Box &box)
 
void onMp4a (const MP4Parser::Box &box)
 
void onStco (MP4Parser::Box &box, bool is64)
 
void onStsc (MP4Parser::Box &box)
 
void onStsd (MP4Parser::Box &box)
 
void onStsz (MP4Parser::Box &box)
 
void onStts (MP4Parser::Box &box)
 
void onTrak ()
 
uint32_t samplesInChunk (Track &t, uint32_t chunkIndex0)
 
void sendWavHeader ()
 
void setSendWavHeader (bool flag) override
 
void setupAudioInfo (AudioFormat format, const uint8_t *entryData, size_t entrySize)
 
void setupParser ()
 
void writeBlocking (Print *out, uint8_t *data, size_t len)
 
void writeVideo (uint8_t *data, size_t size)
 

Static Protected Member Functions

static StscEntry readStscEntry (const uint8_t *p)
 
static SttsEntry readSttsEntry (const uint8_t *p)
 
static uint16_t readU16 (const uint8_t *p)
 
static uint32_t readU32 (const uint8_t *p)
 
static uint64_t readU32Widened (const uint8_t *p)
 
static uint64_t readU64 (const uint8_t *p)
 
static void writeAdtsHeader (uint8_t *adts, int aacProfile, int sampleRateIdx, int channelCfg, int frameLen)
 

Protected Attributes

AudioFormat audio_format = AudioFormat::UNKNOWN
 
SingleBuffer< uint8_t > box_accum {0}
 
bool box_accum_active = false
 
uint64_t box_start_file_offset = 0
 
Trackcurrent_chunk_track = nullptr
 
bool current_sample_is_first_for_track = false
 
uint32_t current_sample_size = 0
 
Trackcurrent_sample_track = nullptr
 
Trackcurrent_track
 track currently being parsed (scoped by 'trak')
 
uint32_t dispatched_sample_count = 0
 
AudioInfo info
 
bool is_active = false
 
bool is_notify_active = true
 
bool is_wav_header_sent = false
 
bool mdat_seen = false
 
Vector< uint8_t > nal_tmp
 scratch buffer for Annex-B conversion
 
Vector< AudioInfoSupport * > notify_vector
 
Trackp_audio_track = nullptr
 
Printp_output_audio = nullptr
 
Printp_print = nullptr
 
SeekableSourcep_seek_source = nullptr
 
SpoolStorageFactoryp_spool_factory = nullptr
 
Printp_video_out = nullptr
 
VideoOutputp_video_out_video = nullptr
 
Trackp_video_track = nullptr
 first video track found
 
MP4Parser parser
 
int64_t quickstart_bytes_remaining = -1
 
Vector< uint8_t > sample_buffer
 
size_t sample_buffer_filled = 0
 
uint32_t samples_left_in_chunk = 0
 
bool send_wav_header = false
 
bool send_wav_header_explicit = false
 
bool stsz_header_pending = true
 
uint32_t total_bytes_received = 0
 
Vector< Track * > tracks
 

Detailed Description

DemuxerMP4 extracts both the audio and (H.264) video track from a general, interleaved MP4/ISO-BMFF stream - unlike M4AAudioDemuxer/ M4AAudioFileDemuxer, which only handle a single (audio) track.

This is a streaming (forward-only) demuxer: it does not need a seekable source, so it works directly over e.g. an HTTP download (URLStream) or an SD file read sequentially with StreamCopy - the same way DemuxerAVI is used. It relies on the file being "faststart" muxed (moov before mdat, e.g. ffmpeg ... -movflags +faststart) - the same requirement MP4Parser and the M4A demuxers already document.

How the interleaving is resolved without seeking: once 'moov' has been fully parsed, every track's stsz (sample sizes) + stsc (sample-to-chunk)

Note
v1 scope: one video track (H.264/avc1 only - HEVC is detected and skipped with a warning) and one audio track (AAC or ALAC). Video output is the raw H.264 Annex-B elementary stream (SPS/PPS from avcC converted to Annex-B and prepended before the first frame) via VideoOutput - there is no pixel decoder anywhere in this library, same scope boundary as DemuxerAVI. No stts/timing support yet - write() dispatches samples as soon as they are complete; pacing is the caller's responsibility.
Relationship to ContainerM4A/M4AAudioDemuxer (AudioCodecs/ ContainerM4A.h, AudioCodecs/M4AAudioDemuxer.h): those handle a single audio-only track and implement ContainerDecoder, so they drop straight into AudioPlayer/MultiDecoder - use them if you only need audio out of an .m4a/.mp4. This class is multi-track (audio+video) and implements Demuxer instead, for the video pipeline (VideoPlayer, PacedVideoOutput, MultiVideoDemuxer). Both parse the same MP4 boxes for the audio sample entry (stsd/mp4a/esds for AAC, stsd/alac for ALAC's magic cookie), but this class keeps its own copy (onStsd/onMp4a/onEsds/onAlac below) rather than inheriting M4ACommonDemuxer like the M4A classes do - M4ACommonDemuxer's handlers assume one single-track audio_config, while this class needs per-track state (current_track) plus random-access sample tables (SampleTableStore) for the interleave merge schedule, so folding the two together isn't a straightforward inheritance change. Kept deliberately separate rather than unified; a fix to one track-audio-config parsing path may need to be mirrored in the other.
Author
Phil Schatzmann

Member Typedef Documentation

◆ Codec

Constructor & Destructor Documentation

◆ DemuxerMP4() [1/5]

DemuxerMP4 ( )
inline

This class only demuxes - it does not decode audio itself. Point setOutputAudio() at an EncodedAudioStream (wrapping whatever AudioDecoder matches the track's codec - AAC/ALAC) if you need the audio track decoded; the raw payload (ADTS-wrapped for AAC, raw for ALAC) is written through as-is otherwise. For ALAC, the decoder also needs the magic cookie exposed via audioALACMagicCookie() - configure your decoder with it (e.g. AudioDecoder::setCodecConfig()) once it's available (after the audio track's 'stsd' has been parsed, i.e. once getAudioInfo().format != AudioFormat::UNKNOWN). Point setOutputVideo() at a Print (e.g. a VideoOutput) to receive the demuxed H.264 Annex-B video track; leave unset to ignore video.

◆ DemuxerMP4() [2/5]

DemuxerMP4 ( Print video_out,
Print audio_out 
)
inline

◆ DemuxerMP4() [3/5]

DemuxerMP4 ( VideoOutput video_out,
Print audio_out 
)
inline

◆ DemuxerMP4() [4/5]

DemuxerMP4 ( SeekableSource seekSource)
inline

'seekSource' wraps the same open file this instance will be fed from (e.g. via FileSeekableSource<File>(myFile)) - when set, newly discovered tracks' sample tables (stsz/stco/stsc/stts) are backed by SourceSeekSampleTableStore instead of the RAM-backed default, trading the ~4.5MB (for a feature-length file) RAM cost for small repeated seeks back into 'seekSource' during playback. Must stay valid and open for the lifetime of playback. See setSeekSource().

◆ DemuxerMP4() [5/5]

DemuxerMP4 ( SpoolStorageFactory spoolFactory)
inline

'spoolFactory' provides a fresh SpoolStorage for each of a track's four sample tables as tracks are discovered - when set, backs new tracks' sample tables with SpoolFileSampleTableStore instead of the RAM-backed default. Unlike the SeekableSource overload above, this needs no seekability in the original MP4 source at all (it writes its own local copy as data streams past), at the cost of real disk I/O for both the writes during 'moov' parsing and the seek+reads during 'mdat' playback. See setSpoolStorageFactory().

◆ ~DemuxerMP4()

~DemuxerMP4 ( )
inline

Member Function Documentation

◆ addNotifyAudioChange()

virtual void addNotifyAudioChange ( AudioInfoSupport bi)
inlinevirtualinherited

◆ advanceChunkIfNeeded()

void advanceChunkIfNeeded ( )
inlineprotected

Picks whichever track's next not-yet-consumed chunk comes first in the file (by chunk_offset) and makes it the active chunk - an incremental two-way merge instead of precomputing a whole-file schedule: each track's own chunk_offsets are already ascending (a muxer writes each track's chunks in file order), so the merged cross-track order falls out of comparing just the next pending chunk_offset per track, in O(1) per call instead of materializing and sorting every chunk from every track upfront.

◆ audioALACMagicCookie()

Vector< uint8_t > & audioALACMagicCookie ( )
inline

ALAC magic cookie (the 'alac' box payload, without its own size/type prefix) needed to configure an external ALAC decoder - empty unless getAudioInfo().format == AudioFormat::ALAC.

◆ 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.

◆ beginBoxAccum()

bool beginBoxAccum ( const MP4Parser::Box box)
inlineprotected

Call at the top of every box_accum-using handler. Returns true the first time it's called for a given box (i.e. right when accumulation starts), false on continuations - callers that need to (re)initialize per-box state (e.g. onStsz's stsz_header_pending) should key off that.

◆ boxPayloadFileOffset()

uint64_t boxPayloadFileOffset ( )
inlineprotected

Absolute file offset of the first byte of this box's payload (box_accum's content), i.e. right after the box's own 8-byte size+type header - used, plus each table's own sub-header size on top, to tell a SourceSeekSampleTableStore where a table's first entry lives on disk.

Deliberately based on box_start_file_offset (captured once, at the box's first delivery - see beginBoxAccum()) rather than computed from total_bytes_received/box_accum.available() at entry-iteration time: MP4Parser advances its own internal fileOffset to the box's end as soon as an incremental box starts (see startIncrementalBox() in MP4Parser.h), before the box is actually fully delivered - a formula relying on "bytes received so far" at the time entries are iterated (which only happens on the box's last delivery) silently used the wrong file position for any box large enough to span multiple write() calls (which every sample table in a feature-length file is) - confirmed by hex-dumping the file at the computed offset and finding it landed inside 'mdat', nowhere near the actual table.

◆ clearNotifyAudioChange()

virtual void clearNotifyAudioChange ( )
inlinevirtualinherited

Deletes all change notify subscriptions.

Reimplemented in RTSPClient< TcpClient, UdpSocket >.

◆ configureSpoolStores()

void configureSpoolStores ( Track t)
inlineprotected

Swaps a track's four sample tables for spool-backed stores, one SpoolStorage per table obtained from p_spool_factory. Guarded so it only ever runs once per track even if onHdlr() somehow saw its kind change or got called again.

◆ dispatchAudio()

void dispatchAudio ( Track t,
const uint8_t *  data,
size_t  size,
bool  isFirst 
)
inlineprotected

◆ dispatchSample()

void dispatchSample ( Track t,
const uint8_t *  data,
size_t  size,
bool  isFirst 
)
inlineprotected

◆ dispatchVideo()

void dispatchVideo ( Track t,
const uint8_t *  data,
size_t  size,
bool  isFirst 
)
inlineprotected

◆ end()

void end ( )
inlineoverridevirtual

Reimplemented from AudioDecoder.

◆ endBoxAccum()

void endBoxAccum ( )
inlineprotected

Call once a box_accum-using handler has fully processed a complete box.

◆ feed()

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

Feeds raw mdat bytes; accumulates until the current sample is complete, dispatches it, and moves on - possibly switching tracks at chunk boundaries per the incremental cross-track merge (see advanceChunkIfNeeded()).

◆ flushVideo()

void flushVideo ( )
inlineprotected

◆ freeTracks()

void freeTracks ( )
inlineprotected

◆ getAudioInfo()

AudioInfoFormat getAudioInfo ( )
inlineoverridevirtual

Common audio info (sample_rate/channels/bits_per_sample), extended with the parsed codec format tag - the same AudioInfoFormat type is also provided by DemuxerAVI. Named getAudioInfo() rather than audioInfo() because AudioDecoder already declares a virtual AudioInfo audioInfo() (returning the plain, unextended type by value) - by-value virtual returns can't be covariantly widened in C++, so reusing that name for a subclass-returning version isn't possible (it would be a hard "invalid covariant return type" error, not silent hiding).

Implements Demuxer.

◆ getOutput()

Print * getOutput ( )
inlineinherited

◆ getVideoInfo()

VideoInfo getVideoInfo ( )
inlineoverridevirtual

Common video info (width/height/format/frame_size/total_file_size), analogous to audioInfo() - the same VideoInfo type is also provided by DemuxerAVI. format is VideoFormat::H264 (the only video codec this class demuxes) once the video track's 'stsd' has been parsed, UNKNOWN before that or for an unsupported codec (e.g. HEVC). frame_size is always 0 (H264 frame size varies) - kept for symmetry with DemuxerAVI, whose raw pixel formats do have a fixed per-frame size. total_file_size has no declared-upfront equivalent in MP4 (no single header field states it, unlike AVI's RIFF header), so it reports the number of bytes received via write() so far instead - only equal to the true total once the whole stream has been fed in.

Implements Demuxer.

◆ 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 ISO base media 'ftyp' box (4-byte box size, then "ftyp" at offset 4) - the standard start of an MP4/M4A file - see Demuxer::isValid().

Reimplemented from Demuxer.

◆ mime()

const char * mime ( )
inlineoverridevirtual

Provides the audio mime (AudioFormat::UNKNOWN/nullptr until the audio track's 'stsd' has been parsed - see getAudioInfo())

Implements Demuxer.

◆ mimeVideo()

const char * mimeVideo ( )
inlineoverridevirtual

Provides the container mime.

Implements Demuxer.

◆ notifyAudioChange()

void notifyAudioChange ( AudioInfo  info)
inlineprotectedinherited

◆ onAc3()

void onAc3 ( const MP4Parser::Box box)
inlineprotected

AC-3 frames are self-synchronizing (each frame starts with its own 0x0B77 sync word and carries its own sample rate/channel info), so - unlike onMp4a/onAlac - there is no child config box to parse here.

◆ onAlac()

void onAlac ( const MP4Parser::Box box)
inlineprotected

◆ onAvc1()

void onAvc1 ( const MP4Parser::Box box)
inlineprotected

◆ onAvcC()

void onAvcC ( const MP4Parser::Box box)
inlineprotected

◆ onEsds()

void onEsds ( const MP4Parser::Box box)
inlineprotected

◆ onHdlr()

void onHdlr ( MP4Parser::Box box)
inlineprotected

◆ onHevc()

void onHevc ( const MP4Parser::Box box)
inlineprotected

◆ onMdat()

void onMdat ( MP4Parser::Box box)
inlineprotected

◆ onMdhd()

void onMdhd ( MP4Parser::Box box)
inlineprotected

'mdhd' (in 'mdia', scoped by the enclosing 'trak'): captures this track's own timescale (ticks/second), needed together with 'stts' to compute each sample's scheduled presentation time.

◆ onMp4a()

void onMp4a ( const MP4Parser::Box box)
inlineprotected

◆ onStco()

void onStco ( MP4Parser::Box box,
bool  is64 
)
inlineprotected

◆ onStsc()

void onStsc ( MP4Parser::Box box)
inlineprotected

◆ onStsd()

void onStsd ( MP4Parser::Box box)
inlineprotected

◆ onStsz()

void onStsz ( MP4Parser::Box box)
inlineprotected

◆ onStts()

void onStts ( MP4Parser::Box box)
inlineprotected

'stts' (time-to-sample): run-length list of {sample_count, sample_delta} - see getVideoInfo(), which derives fps from the first entry's sample_delta.

◆ onTrak()

void onTrak ( )
inlineprotected

◆ operator bool()

operator bool ( )
inlineoverridevirtual

Implements AudioWriter.

◆ quickStart()

bool quickStart ( )
inline

Speeds up startup for a "non-faststart" MP4 (moov written after mdat) by locating and parsing 'moov' directly via seek()/readBytes() on the configured SeekableSource (setSeekSource()), instead of streaming through 'mdat' first to reach it. Only box headers (8 bytes each) are read - the payload is skipped via seek() - so this costs a handful of tiny reads regardless of 'mdat's size.

Call after begin(), before feeding data via write() - or just let FileSeekableSource call it automatically (its default behavior).

On success, leaves the SeekableSource positioned at 'mdat', ready for the normal write()-loop to resume there. Returns false (no side effects) if already faststart, no SeekableSource is configured, or a box form this scan doesn't understand (64-bit or "extends to EOF" size) is encountered.

◆ readStscEntry()

static StscEntry readStscEntry ( const uint8_t *  p)
inlinestaticprotected

◆ readSttsEntry()

static SttsEntry readSttsEntry ( const uint8_t *  p)
inlinestaticprotected

◆ readU16()

static uint16_t readU16 ( const uint8_t *  p)
inlinestaticprotected

◆ readU32()

static uint32_t readU32 ( const uint8_t *  p)
inlinestaticprotected

◆ readU32Widened()

static uint64_t readU32Widened ( const uint8_t *  p)
inlinestaticprotected

◆ readU64()

static uint64_t readU64 ( const uint8_t *  p)
inlinestaticprotected

◆ removeNotifyAudioChange()

virtual bool removeNotifyAudioChange ( AudioInfoSupport bi)
inlinevirtualinherited

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

Reimplemented in RTSPClient< TcpClient, UdpSocket >.

◆ samplesInChunk()

uint32_t samplesInChunk ( Track t,
uint32_t  chunkIndex0 
)
inlineprotected

Number of samples in the given (0-based) chunk index, per 'stsc'. Keeps a per-track cursor rather than rescanning 'stsc' from the start every call - correct as long as chunkIndex0 is non-decreasing across calls for a given track, which holds for the sequential per-chunk consumption in advanceChunkIfNeeded()/feed().

◆ sendWavHeader()

void sendWavHeader ( )
inlineprotected

Synthesizes a valid WAV header (via the shared WAVHeader writer) from the parsed AudioInfo and sends it to p_output_audio, once, before any real audio payload - so a WAVDecoder-based output can bootstrap itself from it. Length is written as streamed/unknown, since the track's length is not known upfront while demuxing. Only ever relevant for a raw-PCM ('lpcm') audio track - not currently produced by this class (AAC/ALAC are the only codecs parsed), but kept symmetric with DemuxerAVI for when PCM tracks are added.

◆ 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 (which calls setOutput() through that base class pointer) still 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 AudioDecoder that matches the audio track's codec, 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 payload 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.

◆ setSeekSource()

void setSeekSource ( SeekableSource seekSource)
inline

See the SeekableSource constructor overload above - can also be called any time before begin(), instead of via the constructor.

◆ setSendWavHeader()

void setSendWavHeader ( bool  flag)
inlineoverrideprotectedvirtual

Overrides the automatic decision of whether a synthetic WAV header is sent to the audio output before any audio payload. By default this is decided automatically from the parsed codec: on whenever isWavFormat() of the parsed format is true (raw PCM), off otherwise (AAC/ALAC, which have their own decoder and don't expect a WAV header). Call this to force it either way instead.

Implements Demuxer.

◆ setSpoolStorageFactory()

void setSpoolStorageFactory ( SpoolStorageFactory spoolFactory)
inline

See the SpoolStorageFactory constructor overload above - can also be called any time before begin(), instead of via the constructor.

◆ setupAudioInfo()

void setupAudioInfo ( AudioFormat  format,
const uint8_t *  entryData,
size_t  entrySize 
)
inlineprotected

Populates the shared AudioInfo (channels/sample_rate/format/mime) from an AudioSampleEntry's fixed 28-byte header (ISO/IEC 14496-12 12.2.3): channelcount at rel-offset 16-17, samplerate (16.16 fixed point, upper 16 bits = Hz) at rel-offset 24-27 - the same layout for any audio sample entry (mp4a, alac, ...), so this is codec-agnostic.

◆ setupParser()

void setupParser ( )
inlineprotected

◆ 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

Partial-write contract (like AVIDecoder::write()): MP4Parser's own internal buffer has finite capacity, so a single call may accept fewer bytes than requested - the caller is expected to call write() again with the remainder, exactly like the underlying Print contract.

Implements AudioWriter.

◆ writeAdtsHeader()

static void writeAdtsHeader ( uint8_t *  adts,
int  aacProfile,
int  sampleRateIdx,
int  channelCfg,
int  frameLen 
)
inlinestaticprotected

◆ writeBlocking()

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

◆ writeVideo()

void writeVideo ( uint8_t *  data,
size_t  size 
)
inlineprotected

Member Data Documentation

◆ audio_format

AudioFormat audio_format = AudioFormat::UNKNOWN
protected

Codec format tag of the (first) audio track - AudioFormat::UNKNOWN until its 'stsd' has been parsed. Kept separately from AudioInfo (see AudioInfoFormat) since AudioInfo itself has no format field.

◆ box_accum

SingleBuffer<uint8_t> box_accum {0}
protected

◆ box_accum_active

bool box_accum_active = false
protected

◆ box_start_file_offset

uint64_t box_start_file_offset = 0
protected

Absolute file offset of the current box_accum-accumulating box's own header - see beginBoxAccum().

◆ current_chunk_track

Track* current_chunk_track = nullptr
protected

◆ current_sample_is_first_for_track

bool current_sample_is_first_for_track = false
protected

◆ current_sample_size

uint32_t current_sample_size = 0
protected

◆ current_sample_track

Track* current_sample_track = nullptr
protected

◆ current_track

Track* current_track
protected
Initial value:
=
nullptr

track currently being parsed (scoped by 'trak')

◆ dispatched_sample_count

uint32_t dispatched_sample_count = 0
protected

◆ id

int id
inherited

custom id to be used by application

◆ info

AudioInfo info
protectedinherited

◆ is_active

bool is_active = false
protected

◆ is_notify_active

bool is_notify_active = true
protectedinherited

◆ is_wav_header_sent

bool is_wav_header_sent = false
protected

◆ mdat_seen

bool mdat_seen = false
protected

◆ nal_tmp

Vector<uint8_t> nal_tmp
protected

scratch buffer for Annex-B conversion

◆ notify_vector

Vector<AudioInfoSupport*> notify_vector
protectedinherited

◆ p_audio_track

Track* p_audio_track = nullptr
protected

first audio track found

◆ p_output_audio

Print* p_output_audio = nullptr
protected

◆ p_print

Print* p_print = nullptr
protectedinherited

◆ p_seek_source

SeekableSource* p_seek_source = nullptr
protected

Set via setSeekSource()/the SeekableSource constructor - when set, onTrak() backs new tracks' sample tables with SourceSeekSampleTableStore instead of the RAM-backed default.

◆ p_spool_factory

SpoolStorageFactory* p_spool_factory = nullptr
protected

Set via setSpoolStorageFactory()/the SpoolStorageFactory constructor

◆ p_video_out

Print* p_video_out = nullptr
protected

◆ p_video_out_video

VideoOutput* p_video_out_video = nullptr
protected

◆ p_video_track

Track* p_video_track = nullptr
protected

first video track found

◆ parser

MP4Parser parser
protected

◆ quickstart_bytes_remaining

int64_t quickstart_bytes_remaining = -1
protected

Set by quickStart() on success, to 'mdat's declared size. -1 (the begin() default) means no boundary active - see write().

◆ sample_buffer

Vector<uint8_t> sample_buffer
protected

◆ sample_buffer_filled

size_t sample_buffer_filled = 0
protected

◆ samples_left_in_chunk

uint32_t samples_left_in_chunk = 0
protected

◆ send_wav_header

bool send_wav_header = false
protected

◆ send_wav_header_explicit

bool send_wav_header_explicit = false
protected

◆ stsz_header_pending

bool stsz_header_pending = true
protected

◆ total_bytes_received

uint32_t total_bytes_received = 0
protected

Bytes received via write() so far this stream - MP4 has no declared total-file-size field to report instead (see getVideoInfo()).

◆ tracks

Vector<Track*> tracks
protected

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