180{
181 FFmpegMuxContext mux;
182 AudioEncodeContext enc;
183
184 auto fail = [&](std::string msg) {
186 m_open.store(
false, std::memory_order_release);
188 };
189
190 if (!mux.open(filepath)) {
191 fail(mux.last_error());
192 return;
193 }
194
195 if (!enc.open(mux, sample_rate, channels, codec_id)) {
196 fail(enc.last_error());
197 return;
198 }
199
200 if (!mux.write_header()) {
201 fail(mux.last_error());
202 return;
203 }
204
205 m_open.store(
true, std::memory_order_release);
206
207 bool ok = true;
208
209 while (true) {
211 if (!item) {
212 std::this_thread::yield();
213 continue;
214 }
215
216 if (std::holds_alternative<FrameChunk>(*item)) {
217 auto& fc = std::get<FrameChunk>(*item);
218 if (!enc.encode_frames(std::span<const double>(fc.samples), fc.num_frames, mux)) {
220 ok = false;
221 }
222 } else if (std::holds_alternative<PlanarChunk>(*item)) {
223 auto& pc = std::get<PlanarChunk>(*item);
224 const auto ch = static_cast<uint32_t>(pc.channels.size());
225 std::vector<double> interleaved(static_cast<size_t>(pc.num_frames) * ch);
226
227 for (uint32_t f = 0; f < pc.num_frames; ++f) {
228 for (uint32_t c = 0; c < ch; ++c)
229 interleaved[(size_t)f * ch + c] = pc.channels[c][f];
230 }
231
232 if (!enc.encode_frames(interleaved, pc.num_frames, mux)) {
234 ok = false;
235 }
236 } else {
237 if (ok && !enc.drain(mux)) {
239 ok = false;
240 }
241 mux.close();
242 m_open.store(
false, std::memory_order_release);
244 return;
245 }
246 }
247}
std::promise< bool > m_close_promise
std::unique_ptr< Memory::LockFreeQueue< WorkItem, k_queue_capacity > > m_queue
void set_error(std::string msg)
std::atomic< bool > m_open