diff --git a/src/lib/crypto/Base64.cxx b/src/lib/crypto/Base64.cxx
index 58910a020..812e5096c 100644
--- a/src/lib/crypto/Base64.cxx
+++ b/src/lib/crypto/Base64.cxx
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 Max Kellermann <max.kellermann@gmail.com>
+ * Copyright 2019-2022 Max Kellermann <max.kellermann@gmail.com>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,7 +30,6 @@
 #include "Base64.hxx"
 #include "lib/ffmpeg/Error.hxx"
 #include "util/StringView.hxx"
-#include "util/WritableBuffer.hxx"
 
 extern "C" {
 #include <libavutil/base64.h>
@@ -39,7 +38,7 @@ extern "C" {
 #include <string>
 
 size_t
-DecodeBase64(WritableBuffer<void> out, StringView in)
+DecodeBase64(std::span<std::byte> out, StringView in)
 {
 	/* since av_base64_decode() wants a null-terminated string, we
 	   need to make a copy here and null-terminate it */
@@ -48,9 +47,9 @@ DecodeBase64(WritableBuffer<void> out, StringView in)
 }
 
 size_t
-DecodeBase64(WritableBuffer<void> out, const char *in)
+DecodeBase64(std::span<std::byte> out, const char *in)
 {
-	int nbytes = av_base64_decode((uint8_t *)out.data, in, out.size);
+	int nbytes = av_base64_decode((uint8_t *)out.data(), in, out.size());
 	if (nbytes < 0)
 		throw MakeFfmpegError(nbytes, "Base64 decoder failed");
 
diff --git a/src/lib/crypto/Base64.hxx b/src/lib/crypto/Base64.hxx
index 1997eca88..a9e8d4679 100644
--- a/src/lib/crypto/Base64.hxx
+++ b/src/lib/crypto/Base64.hxx
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 Max Kellermann <max.kellermann@gmail.com>
+ * Copyright 2019-2022 Max Kellermann <max.kellermann@gmail.com>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,12 +27,11 @@
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef BASE64_HXX
-#define BASE64_HXX
+#pragma once
 
 #include <cstddef>
+#include <span>
 
-template<typename T> struct WritableBuffer;
 struct StringView;
 
 constexpr size_t
@@ -45,12 +44,10 @@ CalculateBase64OutputSize(size_t in_size) noexcept
  * Throws on error.
  */
 size_t
-DecodeBase64(WritableBuffer<void> out, StringView in);
+DecodeBase64(std::span<std::byte> out, StringView in);
 
 /**
  * Throws on error.
  */
 size_t
-DecodeBase64(WritableBuffer<void> out, const char *in);
-
-#endif
+DecodeBase64(std::span<std::byte> out, const char *in);
diff --git a/src/lib/xiph/VorbisPicture.cxx b/src/lib/xiph/VorbisPicture.cxx
index 51df21390..dcdf75efc 100644
--- a/src/lib/xiph/VorbisPicture.cxx
+++ b/src/lib/xiph/VorbisPicture.cxx
@@ -22,7 +22,6 @@
 #include "tag/Id3Picture.hxx"
 #include "tag/Handler.hxx"
 #include "util/StringView.hxx"
-#include "util/WritableBuffer.hxx"
 #include "config.h"
 
 #include <memory>
@@ -36,7 +35,7 @@ ScanVorbisPicture(StringView value, TagHandler &handler) noexcept
 		return;
 
 	size_t debase64_size = CalculateBase64OutputSize(value.size);
-	auto debase64_buffer = std::make_unique<uint8_t[]>(debase64_size);
+	auto debase64_buffer = std::make_unique<std::byte[]>(debase64_size);
 
 	try {
 		debase64_size =