42 std::string filename = file.
getURL();
51 std::array<uint8_t, AVI_HEADER_SIZE> avi_header = {};
52 unsigned header_pos = 0;
54 auto AVIOUT4 = [&](std::string_view s) {
55 assert(s.size() == 4);
59 auto AVIOUTw = [&](uint16_t w) {
61 header_pos +=
sizeof(w);
63 auto AVIOUTd = [&](uint32_t d) {
65 header_pos +=
sizeof(d);
68 auto len1 = s.size() + 1;
70 header_pos += narrow<unsigned>((len1 + 1) & ~1);
73 bool hasAudio = audioRate != 0;
77 AVIOUTd(AVI_HEADER_SIZE + written - 8 +
unsigned(index.size() *
sizeof(
Endian::L32)));
80 auto main_list = header_pos;
86 AVIOUTd(uint32_t(1000000 / fps));
92 AVIOUTd(hasAudio? 2 : 1);
103 AVIOUTd(4 + 8 + 56 + 8 + 40);
114 AVIOUTd(uint32_t(1000000 * fps));
118 AVIOUTd(uint32_t(~0));
130 AVIOUTd(width * height * 4);
138 uint16_t bitsPerSample = 16;
139 unsigned bytesPerSample = bitsPerSample / 8;
140 unsigned bytesPerFragment = bytesPerSample * channels;
141 unsigned bytesPerSecond = audioRate * bytesPerFragment;
142 unsigned fragments = audioWritten / channels;
146 AVIOUTd(4 + 8 + 56 + 8 + 16);
157 AVIOUTd(bytesPerFragment);
158 AVIOUTd(bytesPerSecond);
162 AVIOUTd(
unsigned(~0));
163 AVIOUTd(bytesPerFragment);
170 AVIOUTw(narrow<uint16_t>(channels));
172 AVIOUTd(bytesPerSecond);
173 AVIOUTw(narrow<uint16_t>(bytesPerFragment));
174 AVIOUTw(bitsPerSample);
190 constexpr size_t size = (4 + 1 + 2 + 1 + 2 + 1) + 22;
191 std::array<char, size> dateStr;
192 time_t
t = time(
nullptr);
193 struct tm *tm = localtime(&
t);
194 size_t dateLen = snprintf(dateStr.data(),
sizeof(dateStr),
"%04d-%02d-%02d", 1900 + tm->tm_year,
195 tm->tm_mon + 1, tm->tm_mday);
196 assert(dateLen < size);
199 AVIOUTd(narrow<uint32_t>(
201 + (4 + 4 + ((versionStr.size() + 1 + 1) & ~1))
202 + (4 + 4 + ((dateLen + 1 + 1) & ~1))
206 AVIOUTd(
unsigned(versionStr.size()) + 1);
209 AVIOUTd(
unsigned(dateLen) + 1);
216 auto nMain = header_pos - main_list - 4;
217 auto nJunk = AVI_HEADER_SIZE - 8 - 12 - header_pos;
222 header_pos = main_list;
224 header_pos = AVI_HEADER_SIZE - 12;
227 AVIOUTd(written + 4);
232 unsigned idxSize = unsigned(index.size()) *
sizeof(
Endian::L32);
233 index[0] = (
'i' << 0) | (
'd' << 8) | (
'x' << 16) | (
'1' << 24);
234 index[1] = idxSize - 8;
235 file.
write(std::span{index});
237 file.
write(avi_header);
276 bool keyFrame = (frames++ % 300 == 0);
278 addAviChunk(subspan<4>(
"00dc"), buffer.size(), buffer.data(), keyFrame ? 0x10 : 0x0);
280 if (!audio.empty()) {
281 assert((audio.size() % channels) == 0);
282 assert(audioRate != 0);
286 auto buf = to_vector<Endian::L16>(audio);
287 addAviChunk(subspan<4>(
"01wb"), audio.size_bytes(), buf.data(), 0);
289 addAviChunk(subspan<4>(
"01wb"), audio.size_bytes(), audio.data(), 0);
291 audioWritten += narrow<uint32_t>(audio.size());