+static AVOnce metacube2_crc_once_control = AV_ONCE_INIT;
+static AVCRC metacube2_crc_table[257];
+
+static void metacube2_crc_init_table_once(void)
+{
+ av_assert0(av_crc_init(metacube2_crc_table, 0, 16, 0x8fdb, sizeof(metacube2_crc_table)) >= 0);
+}
+
+static uint16_t metacube2_compute_crc(const struct metacube2_block_header *hdr)
+{
+ static const int data_len = sizeof(hdr->size) + sizeof(hdr->flags);
+ const uint8_t *data = (uint8_t *)&hdr->size;
+ uint16_t crc;
+
+ ff_thread_once(&metacube2_crc_once_control, metacube2_crc_init_table_once);
+
+ // Metacube2 specifies a CRC start of 0x1234, but its pycrc-derived CRC
+ // includes a finalization step that is done somewhat differently in av_crc().
+ // 0x1234 alone sent through that finalization becomes 0x394a, and then we
+ // need a byte-swap of the CRC value (both on input and output) to account for
+ // differing conventions.
+ crc = av_crc(metacube2_crc_table, 0x4a39, data, data_len);
+ return av_bswap16(crc);
+}
+
+static void finalize_metacube_block_header(AVIOContext *s)
+{
+ struct metacube2_block_header hdr;
+ int len = s->buf_ptr_max - s->buffer;
+ int flags = 0;
+
+ if (s->current_type == AVIO_DATA_MARKER_SYNC_POINT)
+ s->seen_sync_point = 1;
+ else if (s->current_type == AVIO_DATA_MARKER_HEADER)
+ // NOTE: If there are multiple blocks marked METACUBE_FLAGS_HEADER,
+ // only the last one will count. This may become a problem if the
+ // mux flushes halfway through the stream header; if so, we would
+ // need to keep track of and concatenate the different parts.
+ flags |= METACUBE_FLAGS_HEADER;
+ else if (s->seen_sync_point)
+ flags |= METACUBE_FLAGS_NOT_SUITABLE_FOR_STREAM_START;
+
+ memcpy(hdr.sync, METACUBE2_SYNC, sizeof(hdr.sync));
+ AV_WB32(&hdr.size, len - sizeof(hdr));
+ AV_WB16(&hdr.flags, flags);
+ AV_WB16(&hdr.csum, metacube2_compute_crc(&hdr));
+ memcpy(s->buffer, &hdr, sizeof(hdr));
+}
+