arduino-audio-tools
Loading...
Searching...
No Matches
VideoMuxer.h
Go to the documentation of this file.
1#pragma once
2
5
6namespace audio_tools {
7
40 public:
41 VideoMuxer() = default;
42 VideoMuxer(Muxer& muxer) { setMuxer(muxer); }
43
45 void setMuxer(Muxer& muxer) { p_muxer = &muxer; }
46
51 void setAudioSource(Stream& pcm) { p_audio = &pcm; }
52
55 p_audio = &out;
57 audio_info = out.audioInfo();
58 }
59
64 audio_info = info;
66 p_source_audio_info->setAudioInfo(info);
67 } else {
68 LOGI("VideoMuxer: setAudioInfo() source not updated");
69 }
70 }
71
77 void setAudioEncoder(AudioEncoder& encoder) { p_audio_encoder = &encoder; }
78
82 void setVideoSource(VideoFrameSource& video) { p_video = &video; }
83
89 void setVideoEncoder(VideoEncoder& encoder) { p_video_encoder = &encoder; }
90
95 bool begin() {
96 if (p_muxer == nullptr) {
97 LOGE("VideoMuxer: setMuxer() was not called");
98 return false;
99 }
100
101 have_video = false;
102 if (p_video != nullptr) {
103 VideoInfo info = p_video->videoInfo();
104 if (info.fps <= 0 || info.width == 0 || info.height == 0) {
105 LOGE(
106 "VideoMuxer: VideoFrameSource::videoInfo() incomplete "
107 "(width=%d height=%d fps=%f)",
108 (int)info.width, (int)info.height, info.fps);
109 return false;
110 }
112 cfg.width = info.width;
113 cfg.height = info.height;
114 cfg.fps = info.fps;
115 cfg.format = p_video_encoder != nullptr
116 ? p_video_encoder->videoInfo().format
117 : info.format;
118 p_muxer->setVideoInfo(cfg);
119 video_fps = info.fps;
120 video_interval_ms = (uint32_t)(1000.0f / info.fps);
121 video_sink.begin(*p_muxer);
122 have_video = true;
123 }
124
125 have_audio = p_audio != nullptr;
126 if (have_audio) {
127 AudioInfoFormat muxer_audio_info;
128 if (p_audio_encoder != nullptr) {
129 muxer_audio_info = AudioInfoFormat(audio_info);
130 AudioFormat mime_format = fromMime(p_audio_encoder->mime());
131 muxer_audio_info.format = mime_format != AudioFormat::UNKNOWN
132 ? mime_format
134 } else {
135 muxer_audio_info = AudioInfoFormat(audio_info);
136 muxer_audio_info.format = AudioFormat::PCM;
137 }
138 p_muxer->setAudioInfo(muxer_audio_info);
139 sample_rate = muxer_audio_info.sample_rate;
141 (muxer_audio_info.bits_per_sample / 8) * muxer_audio_info.channels;
142 }
143
144 if (!p_muxer->begin()) {
145 LOGE("VideoMuxer: Muxer::begin() failed");
146 return false;
147 }
148
149 if (have_video && p_video_encoder != nullptr) {
150 // routed through video_sink, not *p_muxer directly, so it can
151 // determine each frame's real isKeyFrame status (see
152 // MuxerVideoSink, ContainerCommon.h) instead of defaulting to true
153 p_video_encoder->setOutput(video_sink);
154 p_video_encoder->begin();
155 }
156 if (have_audio && p_audio_encoder != nullptr) {
157 p_audio_encoder->setAudioInfo(audio_info);
158 audio_sink.begin(*p_muxer);
159 p_audio_encoder->setOutput(audio_sink);
160 p_audio_encoder->begin();
161 }
162
165 return true;
166 }
167
169 void end() {
170 if (p_muxer != nullptr) p_muxer->end();
171 }
172
181 size_t copy() {
182 if (have_audio) return copyAudio();
183 if (have_video) return copyVideoPaced() ? 1 : 0;
184 return 0;
185 }
186
187 protected:
188 static constexpr size_t kAudioReadChunkSize = 512;
189
190 Muxer* p_muxer = nullptr;
191 Stream* p_audio = nullptr;
199 bool have_audio = false;
200 bool have_video = false;
201 float video_fps = 0;
202 uint32_t video_interval_ms = 33;
203 uint32_t sample_rate = 0;
204 uint32_t bytes_per_sample = 0;
206 uint32_t video_frame_count = 0;
207
208 size_t copyAudio() {
209 uint8_t buf[kAudioReadChunkSize];
210 size_t n = p_audio->readBytes(buf, sizeof(buf));
211 if (n == 0) return 0;
212
213 p_muxer->setStreamType(StreamContentType::Audio);
214 if (p_audio_encoder != nullptr) {
215 p_audio_encoder->write(buf, n);
216 } else {
217 p_muxer->addAudioFrame(buf, n);
218 }
219
221
222 // catch up: mux/encode every video frame now due, given the audio
223 // time just reached - this, not a timer, is what paces video. Strict
224 // '<' (not '<=') so a duration landing exactly on a frame boundary
225 // doesn't pull one extra frame for the instant at that boundary.
226 if (have_video && sample_rate > 0) {
227 double audio_time_s = (double)audio_samples_written / sample_rate;
228 while ((double)video_frame_count / video_fps < audio_time_s) {
229 if (!copyVideo()) break; // source exhausted
230 }
231 }
232 return n;
233 }
234
235 bool copyVideo() {
236 size_t len = 0;
237 const uint8_t* data = p_video->nextFrame(len);
238 if (data == nullptr || len == 0) return false;
239
240 p_muxer->setStreamType(StreamContentType::Video);
241 if (p_video_encoder != nullptr) {
242 p_video_encoder->write(data, len);
243 } else {
244 bool is_key = p_muxer->getVideoInfo().format == VideoFormat::H264
245 ? isH264KeyFrame(data, len)
246 : true;
247 p_muxer->addVideoFrame(data, len, is_key);
248 }
250 return true;
251 }
252
259 uint32_t start = millis();
260 if (!copyVideo()) return false;
261 uint32_t elapsed = millis() - start;
262 if (elapsed < video_interval_ms) delay(video_interval_ms - elapsed);
263 return true;
264 }
265};
266
267} // namespace audio_tools
#define LOGI(...)
#define LOGE(...)
Encoding of PCM data.
Definition AudioCodecsBase.h:101
Supports changes to the sampling rate, bits and channels.
Definition AudioTypes.h:137
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
Print adapter that writes each write() call to a Muxer as one audio frame (Muxer::addAudioFrame()) - ...
Definition ContainerCommon.h:161
Common interface for muxers (MuxerAVI, MuxerMP4) that combine an already-encoded video track (and opt...
Definition ContainerCommon.h:42
Print sink that writes each frame it receives to a Muxer's video track via addVideoFrame(),...
Definition ContainerCommon.h:137
Definition CodecOpusOgg.h:137
Common interface for video encoders (e.g. H264Encoder, H264EncoderESP32S3 - CodecH264....
Definition CodecVideo.h:89
Pull-based provider of one already-encoded video/image frame at a time - e.g. wraps a camera capture ...
Definition Video.h:92
uint32_t bytes_per_sample
Definition VideoMuxer.h:204
VideoEncoder * p_video_encoder
Definition VideoMuxer.h:196
bool have_video
Definition VideoMuxer.h:200
Muxer * p_muxer
Definition VideoMuxer.h:190
uint32_t sample_rate
Definition VideoMuxer.h:203
float video_fps
Definition VideoMuxer.h:201
MuxerAudioSink audio_sink
Definition VideoMuxer.h:198
void setAudioEncoder(AudioEncoder &encoder)
Definition VideoMuxer.h:77
VideoMuxer(Muxer &muxer)
Definition VideoMuxer.h:42
void setMuxer(Muxer &muxer)
Defines the Muxer copy() writes to - call before begin().
Definition VideoMuxer.h:45
MuxerVideoSink video_sink
Definition VideoMuxer.h:197
void setAudioSource(Stream &pcm)
Definition VideoMuxer.h:51
void setAudioInfo(AudioInfo info)
Definition VideoMuxer.h:63
bool begin()
Definition VideoMuxer.h:95
AudioInfo audio_info
Definition VideoMuxer.h:193
bool have_audio
Definition VideoMuxer.h:199
uint32_t video_interval_ms
Definition VideoMuxer.h:202
bool copyVideoPaced()
Definition VideoMuxer.h:258
void setVideoSource(VideoFrameSource &video)
Definition VideoMuxer.h:82
AudioInfoSupport * p_source_audio_info
Definition VideoMuxer.h:194
static constexpr size_t kAudioReadChunkSize
Definition VideoMuxer.h:188
void end()
Closes the Muxer.
Definition VideoMuxer.h:169
size_t copyAudio()
Definition VideoMuxer.h:208
AudioEncoder * p_audio_encoder
Definition VideoMuxer.h:192
uint64_t audio_samples_written
Definition VideoMuxer.h:205
uint32_t video_frame_count
Definition VideoMuxer.h:206
void setAudioSource(AudioStream &out)
Defines the AudioSource that we can configure with setAudioInfo().
Definition VideoMuxer.h:54
void setVideoEncoder(VideoEncoder &encoder)
Definition VideoMuxer.h:89
size_t copy()
Definition VideoMuxer.h:181
VideoFrameSource * p_video
Definition VideoMuxer.h:195
Stream * p_audio
Definition VideoMuxer.h:191
bool copyVideo()
Definition VideoMuxer.h:235
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
@ H264
Definition VideoOutput.h:30
@ Audio
Definition Video.h:21
@ Video
Definition Video.h:21
@ PCM
Definition AudioFormat.h:23
@ UNKNOWN
Definition AudioFormat.h:22
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
uint32_t millis()
Returns the milliseconds since the start.
Definition Arduino.h:260
AudioInfo extended with a WAVEFORMATEX-style codec tag (the "wavcode"): 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:56
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
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition CodecOpusOgg.h:58
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition CodecOpusOgg.h:60
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits).
Definition CodecOpusOgg.h:62