arduino-audio-tools
Loading...
Searching...
No Matches
VideoMuxerWithTasks.h
Go to the documentation of this file.
1#pragma once
2
5
6#ifdef __linux__
8#else
10#endif
11
12namespace audio_tools {
13
46 public:
49
51 void setMuxer(Muxer &muxer) { p_muxer = &muxer; }
52
57 void setAudioSource(Stream &pcm) { p_audio = &pcm; }
58
61 p_audio = &out;
63 audio_info = out.audioInfo();
64 }
65
70 void setAudioInfo(AudioInfo info) {
71 audio_info = info;
74 } else {
75 LOGI("VideoMuxerWithTasks: setAudioInfo() source not updated");
76 }
77 }
78
88 void setAudioEncoder(AudioEncoder &encoder) { p_audio_encoder = &encoder; }
89
93 void setVideoSource(VideoFrameSource &video) { p_video = &video; }
94
100 void setVideoEncoder(VideoEncoder &encoder) { p_video_encoder = &encoder; }
101
106 void setMutex(MutexBase &mutex) { p_mutex = &mutex; }
107
112 void setTaskParameters(uint32_t stackSizeWords, uint8_t priority,
113 int core = -1) {
114 task_stack_size = stackSizeWords;
115 task_priority = priority;
116 task_core = core;
117 }
118
123 bool begin() {
124 if (p_muxer == nullptr) {
125 LOGE("VideoMuxerWithTasks: setMuxer() was not called");
126 return false;
127 }
128
129 bool have_video = false;
130 if (p_video != nullptr) {
131 VideoInfo info = p_video->videoInfo();
132 if (info.fps <= 0 || info.width == 0 || info.height == 0) {
133 LOGE(
134 "VideoMuxerWithTasks: VideoFrameSource::videoInfo() incomplete "
135 "(width=%d height=%d fps=%f)",
136 (int)info.width, (int)info.height, info.fps);
137 return false;
138 }
140 cfg.width = info.width;
141 cfg.height = info.height;
142 cfg.fps = info.fps;
143 // with a video encoder, the source's own format describes the raw
144 // picture, not the container - query the encoder's own
145 // VideoEncoder::videoInfo() instead, the reliable way to determine
146 // what actually ends up in the container
147 cfg.format = p_video_encoder != nullptr
149 : info.format;
150 p_muxer->setVideoInfo(cfg);
151 video_interval_ms = (uint32_t)(1000.0f / info.fps);
153 have_video = true;
154 }
155
156 bool have_audio = p_audio != nullptr;
157 if (have_audio) {
158 AudioInfoFormat muxer_audio_info;
159 if (p_audio_encoder != nullptr) {
160 muxer_audio_info = AudioInfoFormat(audio_info);
161 AudioFormat mime_format = fromMime(p_audio_encoder->mime());
162 muxer_audio_info.format = mime_format != AudioFormat::UNKNOWN
163 ? mime_format
165 } else {
166 muxer_audio_info = AudioInfoFormat(audio_info);
167 muxer_audio_info.format = AudioFormat::PCM;
168 }
169 p_muxer->setAudioInfo(muxer_audio_info);
170 }
171
172 if (!p_muxer->begin()) {
173 LOGE("VideoMuxerWithTasks: Muxer::begin() failed");
174 return false;
175 }
176
177 bool ok = true;
178 if (have_video) {
179 if (p_video_encoder != nullptr) {
180 // routed through video_sink, not *p_muxer directly, so it can
181 // determine each frame's real isKeyFrame status (see
182 // MuxerVideoSink) instead of defaulting to true
185 }
186 ok &= video_task.create("VideoMuxerVideoTask", task_stack_size,
188 ok &= video_task.begin([this]() { videoTaskLoop(); });
189 }
190 if (have_audio) {
191 if (p_audio_encoder != nullptr) {
195 }
196 ok &= audio_task.create("VideoMuxerAudioTask", task_stack_size,
198 ok &= audio_task.begin([this]() { audioTaskLoop(); });
199 }
200 return ok;
201 }
202
204 void end() {
205 audio_task.end();
206 video_task.end();
207 if (p_muxer != nullptr) p_muxer->end();
208 }
209
211
212 protected:
217 static constexpr size_t kAudioReadChunkSize = 512;
218
223#ifdef __linux__
224 using DefaultMutex = StdMutex;
225#else
227#endif
228
229 Muxer *p_muxer = nullptr;
230 Stream *p_audio = nullptr;
241 uint32_t task_stack_size = 4096;
242 uint8_t task_priority = 2;
243 int task_core = -1;
244 uint32_t video_interval_ms = 33;
245
254 if (p_audio != nullptr) {
255 uint8_t buf[kAudioReadChunkSize];
256 size_t n = p_audio->readBytes(buf, sizeof(buf));
257 if (n > 0) {
258 LockGuard guard(p_mutex);
260 if (p_audio_encoder != nullptr) {
261 p_audio_encoder->write(buf, n);
262 } else {
263 p_muxer->addAudioFrame(buf, n);
264 }
265 } else {
266 delay(1);
267 }
268 }
269 }
270
276 uint32_t start = millis();
277 if (p_video != nullptr && p_muxer != nullptr) {
278 size_t len = 0;
279 const uint8_t *data = p_video->nextFrame(len);
280 if (data != nullptr && len > 0) {
281 LockGuard guard(p_mutex);
283 if (p_video_encoder != nullptr) {
284 p_video_encoder->write(data, len);
285 } else {
286 bool is_key = p_muxer->getVideoInfo().format == VideoFormat::H264
287 ? isH264KeyFrame(data, len)
288 : true;
289 p_muxer->addVideoFrame(data, len, is_key);
290 }
291 }
292 }
293 uint32_t elapsed = millis() - start;
294 if (elapsed < video_interval_ms) delay(video_interval_ms - elapsed);
295 }
296};
297
298} // 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:98
void setAudioInfo(AudioInfo from) override
Defines the sample rate, number of channels and bits per sample.
Definition AudioCodecsBase.h:107
virtual void setOutput(Print &out_stream) override
Default output assignment (encoders may override to store Print reference)
Definition AudioCodecsBase.h:110
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:131
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:18
Mutex API for non IRQ mutual exclusion between cores. Mutexes are application level locks usually use...
Definition MutexRP2040.h:38
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
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:59
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:150
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:45
void audioTaskLoop()
Definition VideoMuxerWithTasks.h:253
DefaultMutex default_mutex
Definition VideoMuxerWithTasks.h:237
VideoEncoder * p_video_encoder
Definition VideoMuxerWithTasks.h:235
MutexBase * p_mutex
Definition VideoMuxerWithTasks.h:238
void setMutex(MutexBase &mutex)
Definition VideoMuxerWithTasks.h:106
int task_core
Definition VideoMuxerWithTasks.h:243
Muxer * p_muxer
Definition VideoMuxerWithTasks.h:229
Task audio_task
Definition VideoMuxerWithTasks.h:239
void setAudioEncoder(AudioEncoder &encoder)
Definition VideoMuxerWithTasks.h:88
bool isRunning()
Definition VideoMuxerWithTasks.h:210
void setMuxer(Muxer &muxer)
Defines the Muxer both tasks write to - call before begin().
Definition VideoMuxerWithTasks.h:51
MuxerVideoSink video_sink
Definition VideoMuxerWithTasks.h:236
void setAudioSource(Stream &pcm)
Definition VideoMuxerWithTasks.h:57
VideoMuxerWithTasks(Muxer &muxer)
Definition VideoMuxerWithTasks.h:48
void setAudioInfo(AudioInfo info)
Definition VideoMuxerWithTasks.h:70
bool begin()
Definition VideoMuxerWithTasks.h:123
AudioInfo audio_info
Definition VideoMuxerWithTasks.h:232
uint32_t video_interval_ms
Definition VideoMuxerWithTasks.h:244
uint8_t task_priority
Definition VideoMuxerWithTasks.h:242
void setVideoSource(VideoFrameSource &video)
Definition VideoMuxerWithTasks.h:93
AudioInfoSupport * p_source_audio_info
Definition VideoMuxerWithTasks.h:233
static constexpr size_t kAudioReadChunkSize
Definition VideoMuxerWithTasks.h:217
Task video_task
Definition VideoMuxerWithTasks.h:240
void end()
Stops both tasks and closes the Muxer.
Definition VideoMuxerWithTasks.h:204
AudioEncoder * p_audio_encoder
Definition VideoMuxerWithTasks.h:231
void setAudioSource(AudioStream &out)
Defines the AudioSource that we can configure with setAudioInfo()
Definition VideoMuxerWithTasks.h:60
void videoTaskLoop()
Definition VideoMuxerWithTasks.h:275
void setVideoEncoder(VideoEncoder &encoder)
Definition VideoMuxerWithTasks.h:100
VideoFrameSource * p_video
Definition VideoMuxerWithTasks.h:234
Stream * p_audio
Definition VideoMuxerWithTasks.h:230
uint32_t task_stack_size
Definition VideoMuxerWithTasks.h:241
void setTaskParameters(uint32_t stackSizeWords, uint8_t priority, int core=-1)
Definition VideoMuxerWithTasks.h:112
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:86
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:361
@ Audio
Definition Video.h:19
@ Video
Definition Video.h:19
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
MutexRP2040 Mutex
Default Mutex implementation using RP2040 Pico SDK.
Definition MutexRP2040.h:58
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:389
AudioFormat format
Definition AudioFormat.h:398
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 Video.h:102
float fps
Definition Video.h:109
uint16_t height
Frame height in pixels.
Definition Video.h:106
uint16_t width
Frame width in pixels.
Definition Video.h:104
VideoFormat format
Video codec - VideoFormat::UNKNOWN if not (yet) determined.
Definition Video.h:111