arduino-audio-tools
Loading...
Searching...
No Matches
VideoMuxerWithTasks.h
Go to the documentation of this file.
1#pragma once
2
6
7namespace audio_tools {
8
41 public:
44
46 void setMuxer(Muxer &muxer) { p_muxer = &muxer; }
47
52 void setAudioSource(Stream &pcm) { p_audio = &pcm; }
53
56 p_audio = &out;
58 audio_info = out.audioInfo();
59 }
60
65 void setAudioInfo(AudioInfo info) {
66 audio_info = info;
69 } else {
70 LOGI("VideoMuxerWithTasks: setAudioInfo() source not updated");
71 }
72 }
73
83 void setAudioEncoder(AudioEncoder &encoder) { p_audio_encoder = &encoder; }
84
88 void setVideoSource(VideoFrameSource &video) { p_video = &video; }
89
95 void setVideoEncoder(VideoEncoder &encoder) { p_video_encoder = &encoder; }
96
101 void setMutex(MutexBase &mutex) { p_mutex = &mutex; }
102
107 void setTaskParameters(uint32_t stackSizeWords, uint8_t priority,
108 int core = -1) {
109 task_stack_size = stackSizeWords;
110 task_priority = priority;
111 task_core = core;
112 }
113
118 bool begin() {
119 if (p_muxer == nullptr) {
120 LOGE("VideoMuxerWithTasks: setMuxer() was not called");
121 return false;
122 }
123
124 bool have_video = false;
125 if (p_video != nullptr) {
126 VideoInfo info = p_video->videoInfo();
127 if (info.fps <= 0 || info.width == 0 || info.height == 0) {
128 LOGE(
129 "VideoMuxerWithTasks: VideoFrameSource::videoInfo() incomplete "
130 "(width=%d height=%d fps=%f)",
131 (int)info.width, (int)info.height, info.fps);
132 return false;
133 }
135 cfg.width = info.width;
136 cfg.height = info.height;
137 cfg.fps = info.fps;
138 // with a video encoder, the source's own format describes the raw
139 // picture, not the container - query the encoder's own
140 // VideoEncoder::videoInfo() instead, the reliable way to determine
141 // what actually ends up in the container
142 cfg.format = p_video_encoder != nullptr
144 : info.format;
145 p_muxer->setVideoInfo(cfg);
146 video_interval_ms = (uint32_t)(1000.0f / info.fps);
148 have_video = true;
149 }
150
151 bool have_audio = p_audio != nullptr;
152 if (have_audio) {
153 AudioInfoFormat muxer_audio_info;
154 if (p_audio_encoder != nullptr) {
155 muxer_audio_info = AudioInfoFormat(audio_info);
156 AudioFormat mime_format = fromMime(p_audio_encoder->mime());
157 muxer_audio_info.format = mime_format != AudioFormat::UNKNOWN
158 ? mime_format
160 } else {
161 muxer_audio_info = AudioInfoFormat(audio_info);
162 muxer_audio_info.format = AudioFormat::PCM;
163 }
164 p_muxer->setAudioInfo(muxer_audio_info);
165 }
166
167 if (!p_muxer->begin()) {
168 LOGE("VideoMuxerWithTasks: Muxer::begin() failed");
169 return false;
170 }
171
172 bool ok = true;
173 if (have_video) {
174 if (p_video_encoder != nullptr) {
175 // routed through video_sink, not *p_muxer directly, so it can
176 // determine each frame's real isKeyFrame status (see
177 // MuxerVideoSink) instead of defaulting to true
180 }
181 ok &= video_task.create("VideoMuxerVideoTask", task_stack_size,
183 ok &= video_task.begin([this]() { videoTaskLoop(); });
184 }
185 if (have_audio) {
186 if (p_audio_encoder != nullptr) {
190 }
191 ok &= audio_task.create("VideoMuxerAudioTask", task_stack_size,
193 ok &= audio_task.begin([this]() { audioTaskLoop(); });
194 }
195 return ok;
196 }
197
199 void end() {
200 audio_task.end();
201 video_task.end();
202 if (p_muxer != nullptr) p_muxer->end();
203 }
204
206
207 protected:
212 static constexpr size_t kAudioReadChunkSize = 512;
213
218#ifdef __linux__
219 using DefaultMutex = StdMutex;
220#else
222#endif
223
224 Muxer *p_muxer = nullptr;
225 Stream *p_audio = nullptr;
236 uint32_t task_stack_size = 4096;
237 uint8_t task_priority = 2;
238 int task_core = -1;
239 uint32_t video_interval_ms = 33;
240
249 if (p_audio != nullptr) {
250 uint8_t buf[kAudioReadChunkSize];
251 size_t n = p_audio->readBytes(buf, sizeof(buf));
252 if (n > 0) {
253 LockGuard guard(p_mutex);
255 if (p_audio_encoder != nullptr) {
256 p_audio_encoder->write(buf, n);
257 } else {
258 p_muxer->addAudioFrame(buf, n);
259 }
260 } else {
261 delay(1);
262 }
263 }
264 }
265
271 uint32_t start = millis();
272 if (p_video != nullptr && p_muxer != nullptr) {
273 size_t len = 0;
274 const uint8_t *data = p_video->nextFrame(len);
275 if (data != nullptr && len > 0) {
276 LockGuard guard(p_mutex);
278 if (p_video_encoder != nullptr) {
279 p_video_encoder->write(data, len);
280 } else {
281 bool is_key = p_muxer->getVideoInfo().format == VideoFormat::H264
282 ? isH264KeyFrame(data, len)
283 : true;
284 p_muxer->addVideoFrame(data, len, is_key);
285 }
286 }
287 }
288 uint32_t elapsed = millis() - start;
289 if (elapsed < video_interval_ms) delay(video_interval_ms - elapsed);
290 }
291};
292
293} // namespace audio_tools
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGE(...)
Definition AudioLoggerIDF.h:30
Definition Arduino.h:136
virtual size_t readBytes(uint8_t *data, size_t len)
Definition Arduino.h:140
Encoding of PCM data.
Definition AudioCodecsBase.h:101
void setAudioInfo(AudioInfo from) override
Defines the sample rate, number of channels and bits per sample.
Definition AudioCodecsBase.h:110
virtual void setOutput(Print &out_stream) override
Default output assignment (encoders may override to store Print reference)
Definition AudioCodecsBase.h:113
virtual const char * mime()=0
Provides the mime type of the encoded result.
Supports changes to the sampling rate, bits and channels.
Definition AudioTypes.h:132
virtual void setAudioInfo(AudioInfo info)=0
Defines the input AudioInfo.
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:120
virtual AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition BaseStream.h:151
virtual size_t write(const uint8_t *data, size_t len)=0
virtual bool begin()=0
RAII implementaion using a Mutex: Only a few microcontrollers provide lock guards,...
Definition LockGuard.h:17
Empty Mutex implementation which does nothing.
Definition Mutex.h:15
Common interface for muxers (MuxerAVI, MuxerMP4) that combine an already-encoded video track (and opt...
Definition ContainerCommon.h:42
virtual void setVideoInfo(MuxerVideoConfig config)=0
Defines the video track configuration - call before begin()
virtual MuxerVideoConfig getVideoInfo()=0
Provides the video track configuration.
virtual void setAudioInfo(AudioInfoFormat info)=0
virtual size_t addAudioFrame(const uint8_t *data, size_t len)=0
virtual size_t addVideoFrame(const uint8_t *data, size_t len, bool isKeyFrame=true)=0
virtual void end()=0
Closes the muxer.
virtual void setStreamType(StreamContentType type)=0
Selects whether write() feeds the video or the audio track.
virtual bool begin()=0
Print sink that writes each frame it receives to a Muxer's video track via addVideoFrame(),...
Definition ContainerCommon.h:137
void begin(Muxer &muxer)
Definition ContainerCommon.h:139
Mutex implemntation based on std::mutex.
Definition Mutex.h:16
FreeRTOS task.
Definition Task.h:26
bool isRunning()
true if the task was created and is not suspended
Definition Task.h:124
bool create(const char *name, int stackSizeWords, int priority=1, int core=-1)
Definition Task.h:54
void end()
suspends the task
Definition Task.h:105
bool begin(std::function< void()> process)
Definition Task.h:94
Common interface for video encoders (e.g. H264Encoder, H264EncoderESP32S3 - CodecH264....
Definition CodecVideo.h:89
virtual size_t write(const uint8_t *data, size_t len)=0
virtual void setOutput(Print &out)=0
Defines the target the encoded bitstream is written to.
virtual bool begin()=0
Initializes the encoder (allocates its picture buffers, etc).
virtual VideoInfo videoInfo()=0
Pull-based provider of one already-encoded video/image frame at a time - e.g. wraps a camera capture ...
Definition Video.h:92
virtual const uint8_t * nextFrame(size_t &len)=0
virtual VideoInfo videoInfo()=0
Feeds a Muxer (MuxerAVI, MuxerMP4, ...) from two background Tasks instead of a single loop()/copy() c...
Definition VideoMuxerWithTasks.h:40
void audioTaskLoop()
Definition VideoMuxerWithTasks.h:248
DefaultMutex default_mutex
Definition VideoMuxerWithTasks.h:232
VideoEncoder * p_video_encoder
Definition VideoMuxerWithTasks.h:230
MutexBase * p_mutex
Definition VideoMuxerWithTasks.h:233
void setMutex(MutexBase &mutex)
Definition VideoMuxerWithTasks.h:101
int task_core
Definition VideoMuxerWithTasks.h:238
Muxer * p_muxer
Definition VideoMuxerWithTasks.h:224
Task audio_task
Definition VideoMuxerWithTasks.h:234
void setAudioEncoder(AudioEncoder &encoder)
Definition VideoMuxerWithTasks.h:83
bool isRunning()
Definition VideoMuxerWithTasks.h:205
void setMuxer(Muxer &muxer)
Defines the Muxer both tasks write to - call before begin().
Definition VideoMuxerWithTasks.h:46
MuxerVideoSink video_sink
Definition VideoMuxerWithTasks.h:231
void setAudioSource(Stream &pcm)
Definition VideoMuxerWithTasks.h:52
VideoMuxerWithTasks(Muxer &muxer)
Definition VideoMuxerWithTasks.h:43
void setAudioInfo(AudioInfo info)
Definition VideoMuxerWithTasks.h:65
bool begin()
Definition VideoMuxerWithTasks.h:118
AudioInfo audio_info
Definition VideoMuxerWithTasks.h:227
uint32_t video_interval_ms
Definition VideoMuxerWithTasks.h:239
uint8_t task_priority
Definition VideoMuxerWithTasks.h:237
void setVideoSource(VideoFrameSource &video)
Definition VideoMuxerWithTasks.h:88
AudioInfoSupport * p_source_audio_info
Definition VideoMuxerWithTasks.h:228
static constexpr size_t kAudioReadChunkSize
Definition VideoMuxerWithTasks.h:212
Task video_task
Definition VideoMuxerWithTasks.h:235
void end()
Stops both tasks and closes the Muxer.
Definition VideoMuxerWithTasks.h:199
AudioEncoder * p_audio_encoder
Definition VideoMuxerWithTasks.h:226
void setAudioSource(AudioStream &out)
Defines the AudioSource that we can configure with setAudioInfo()
Definition VideoMuxerWithTasks.h:55
void videoTaskLoop()
Definition VideoMuxerWithTasks.h:270
void setVideoEncoder(VideoEncoder &encoder)
Definition VideoMuxerWithTasks.h:95
VideoFrameSource * p_video
Definition VideoMuxerWithTasks.h:229
Stream * p_audio
Definition VideoMuxerWithTasks.h:225
uint32_t task_stack_size
Definition VideoMuxerWithTasks.h:236
void setTaskParameters(uint32_t stackSizeWords, uint8_t priority, int core=-1)
Definition VideoMuxerWithTasks.h:107
bool isH264KeyFrame(const uint8_t *data, size_t len)
True if the given Annex-B H.264 access unit contains an IDR slice NAL unit (nal_unit_type 5) - the re...
Definition Video.h:52
AudioFormat
Audio format codes used by Microsoft e.g. in avi or wav files.
Definition AudioFormat.h:21
AudioFormat fromMime(const char *mime)
Best-effort inverse of toMime(): maps a mime type (e.g. an AudioEncoder's mime()) back to the AudioFo...
Definition AudioFormat.h:363
@ Audio
Definition Video.h:21
@ Video
Definition Video.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
void delay(uint32_t ms)
Definition Arduino.h:259
StdMutex Mutex
Default Mutex implementation using std::mutex.
Definition Mutex.h:42
uint32_t millis()
Returns the milliseconds since the start.
Definition Arduino.h:260
AudioInfo extended with a WAVEFORMATEX-style codec tag (the "wav code"): identifies the codec (PCM,...
Definition AudioFormat.h:392
AudioFormat format
Definition AudioFormat.h:401
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:51
Shared video track configuration for muxers (MuxerAVI, MuxerMP4) - call before begin().
Definition ContainerCommon.h:11
float fps
Definition ContainerCommon.h:14
uint16_t height
Definition ContainerCommon.h:13
uint16_t width
Definition ContainerCommon.h:12
VideoFormat format
Definition ContainerCommon.h:15
Basic video information (width/height/codec/frame size), analogous to AudioInfo - common to both Demu...
Definition VideoOutput.h:49
float fps
Definition VideoOutput.h:56
uint16_t height
Frame height in pixels.
Definition VideoOutput.h:53
uint16_t width
Frame width in pixels.
Definition VideoOutput.h:51
VideoFormat format
Video codec - VideoFormat::UNKNOWN if not (yet) determined.
Definition VideoOutput.h:58