45 std::string filename = file.
getURL();
54 std::array<uint8_t, AVI_HEADER_SIZE> avi_header = {};
55 unsigned header_pos = 0;
57 auto AVIOUT4 = [&](std::string_view s) {
58 assert(s.size() == 4);
62 auto AVIOUTw = [&](uint16_t w) {
64 header_pos +=
sizeof(w);
66 auto AVIOUTd = [&](uint32_t d) {
68 header_pos +=
sizeof(d);
71 auto len1 = s.size() + 1;
73 header_pos += narrow<unsigned>((len1 + 1) & ~1);
76 bool hasAudio = audioRate != 0;
80 AVIOUTd(AVI_HEADER_SIZE + written - 8 +
unsigned(index.size() *
sizeof(
Endian::L32)));
83 auto main_list = header_pos;
89 AVIOUTd(uint32_t(1000000 / fps));
95 AVIOUTd(hasAudio? 2 : 1);
106 AVIOUTd(4 + 8 + 56 + 8 + 40);
117 AVIOUTd(uint32_t(1000000 * fps));
121 AVIOUTd(uint32_t(~0));
133 AVIOUTd(width * height * 4);
141 uint16_t bitsPerSample = 16;
142 unsigned bytesPerSample = bitsPerSample / 8;
143 unsigned bytesPerFragment = bytesPerSample * channels;
144 unsigned bytesPerSecond = audioRate * bytesPerFragment;
145 unsigned fragments = audioWritten / channels;
149 AVIOUTd(4 + 8 + 56 + 8 + 16);
160 AVIOUTd(bytesPerFragment);
161 AVIOUTd(bytesPerSecond);
165 AVIOUTd(
unsigned(~0));
166 AVIOUTd(bytesPerFragment);
173 AVIOUTw(narrow<uint16_t>(channels));
175 AVIOUTd(bytesPerSecond);
176 AVIOUTw(narrow<uint16_t>(bytesPerFragment));
177 AVIOUTw(bitsPerSample);
193 constexpr size_t size = (4 + 1 + 2 + 1 + 2 + 1) + 22;
194 std::array<char, size> dateStr;
195 time_t
t = time(
nullptr);
196 const struct tm* tm = localtime(&
t);
197 size_t dateLen = snprintf(dateStr.data(),
sizeof(dateStr),
"%04d-%02d-%02d", 1900 + tm->tm_year,
198 tm->tm_mon + 1, tm->tm_mday);
199 assert(dateLen < size);
202 AVIOUTd(narrow<uint32_t>(
204 + (4 + 4 + ((versionStr.size() + 1 + 1) & ~1))
205 + (4 + 4 + ((dateLen + 1 + 1) & ~1))
209 AVIOUTd(
unsigned(versionStr.size()) + 1);
212 AVIOUTd(
unsigned(dateLen) + 1);
219 auto nMain = header_pos - main_list - 4;
220 auto nJunk = AVI_HEADER_SIZE - 8 - 12 - header_pos;
225 header_pos = main_list;
227 header_pos = AVI_HEADER_SIZE - 12;
230 AVIOUTd(written + 4);
235 unsigned idxSize = unsigned(index.size()) *
sizeof(
Endian::L32);
236 index[0] = (
'i' << 0) | (
'd' << 8) | (
'x' << 16) | (
'1' << 24);
237 index[1] = idxSize - 8;
238 file.
write(std::span{index});
240 file.
write(avi_header);
246void AviWriter::addAviChunk(std::span<const char, 4> tag, std::span<const uint8_t> data,
unsigned flags)
278 bool keyFrame = (frames++ % 300 == 0);
280 addAviChunk(subspan<4>(
"00dc"), buffer, keyFrame ? 0x10 : 0x0);
282 if (!audio.empty()) {
283 assert((audio.size() % channels) == 0);
284 assert(audioRate != 0);
288 auto buf = to_vector<Endian::L16>(audio);
289 addAviChunk(subspan<4>(
"01wb"),
as_byte_span(std::span{buf}), 0);
291 addAviChunk(subspan<4>(
"01wb"),
as_byte_span(audio), 0);
293 audioWritten += narrow<uint32_t>(audio.size());