diff --git a/api/funkwhale_api/music/metadata.py b/api/funkwhale_api/music/metadata.py
index feec90cc76d47f29013be263dfacb0f94aefa9f2..801ea6a9badc141c5e06e2eb3f69caa5045076d1 100644
--- a/api/funkwhale_api/music/metadata.py
+++ b/api/funkwhale_api/music/metadata.py
@@ -70,6 +70,45 @@ def clean_id3_pictures(apic):
     return pictures
 
 
+def get_mp4_tag(f, k):
+    if k == "pictures":
+        return f.get("covr")
+    raw_value = f.get(k, None)
+
+    if not raw_value:
+        raise TagNotFound(k)
+
+    value = raw_value[0]
+    try:
+        return value.decode()
+    except AttributeError:
+        return value
+
+
+def get_mp4_position(raw_value):
+    return raw_value[0]
+
+
+def clean_mp4_pictures(raw_pictures):
+    pictures = []
+    for p in list(raw_pictures):
+        if p.imageformat == p.FORMAT_JPEG:
+            mimetype = "image/jpeg"
+        elif p.imageformat == p.FORMAT_PNG:
+            mimetype = "image/png"
+        else:
+            continue
+        pictures.append(
+            {
+                "mimetype": mimetype,
+                "content": bytes(p),
+                "description": "",
+                "type": mutagen.id3.PictureType.COVER_FRONT,
+            }
+        )
+    return pictures
+
+
 def get_flac_tag(f, k):
     if k == "pictures":
         return f.pictures
@@ -216,6 +255,33 @@ CONF = {
             "copyright": {"field": "TCOP"},
         },
     },
+    "MP4": {
+        "getter": get_mp4_tag,
+        "clean_pictures": clean_mp4_pictures,
+        "fields": {
+            "position": {"field": "trkn", "to_application": get_mp4_position},
+            "disc_number": {"field": "disk", "to_application": get_mp4_position},
+            "title": {"field": "©nam"},
+            "artist": {"field": "©ART"},
+            "album_artist": {"field": "aART"},
+            "album": {"field": "©alb"},
+            "date": {"field": "©day"},
+            "musicbrainz_albumid": {
+                "field": "----:com.apple.iTunes:MusicBrainz Album Id"
+            },
+            "musicbrainz_artistid": {
+                "field": "----:com.apple.iTunes:MusicBrainz Artist Id"
+            },
+            "genre": {"field": "©gen"},
+            "musicbrainz_albumartistid": {
+                "field": "----:com.apple.iTunes:MusicBrainz Album Artist Id"
+            },
+            "mbid": {"field": "----:com.apple.iTunes:MusicBrainz Track Id"},
+            "pictures": {},
+            "license": {"field": "----:com.apple.iTunes:LICENSE"},
+            "copyright": {"field": "cprt"},
+        },
+    },
     "FLAC": {
         "getter": get_flac_tag,
         "clean_pictures": clean_flac_pictures,
diff --git a/api/funkwhale_api/music/utils.py b/api/funkwhale_api/music/utils.py
index bf3a0daf63b5e79499942deeed597238e1d6426f..09c8cbd122a6099cee8a0e9874fc1fe0ce1eea37 100644
--- a/api/funkwhale_api/music/utils.py
+++ b/api/funkwhale_api/music/utils.py
@@ -34,6 +34,8 @@ AUDIO_EXTENSIONS_AND_MIMETYPE = [
     ("ogg", "audio/ogg"),
     ("opus", "audio/opus"),
     ("mp3", "audio/mpeg"),
+    ("aac", "audio/x-m4a"),
+    ("m4a", "audio/x-m4a"),
     ("flac", "audio/x-flac"),
     ("flac", "audio/flac"),
 ]
diff --git a/api/tests/music/test.m4a b/api/tests/music/test.m4a
new file mode 100644
index 0000000000000000000000000000000000000000..57b65b7b53489c85cb7a9e5ca5fa92fa976c35ea
Binary files /dev/null and b/api/tests/music/test.m4a differ
diff --git a/api/tests/music/test_metadata.py b/api/tests/music/test_metadata.py
index 716d9c97948521edb4ebf70678d9f9f303cda1c5..9a3826ce3832050c8ba15188129b4dc5548a480f 100644
--- a/api/tests/music/test_metadata.py
+++ b/api/tests/music/test_metadata.py
@@ -149,6 +149,7 @@ def test_can_get_metadata_from_id3_mp3_file(field, value):
         "sample.flac",
         "with_cover.ogg",
         "with_cover.opus",
+        "test.m4a",
     ],
 )
 def test_can_get_pictures(name):
@@ -189,6 +190,35 @@ def test_can_get_metadata_from_flac_file(field, value):
     assert data.get(field) == value
 
 
+@pytest.mark.parametrize(
+    "field,value",
+    [
+        ("title", "Peer Gynt Suite no. 1, op. 46: I. Morning"),
+        ("artist", "Edvard Grieg"),
+        ("album_artist", "Edvard Grieg; Musopen Symphony Orchestra"),
+        ("album", "Peer Gynt Suite no. 1, op. 46"),
+        ("date", "2012-08-15"),
+        ("position", 1),
+        ("disc_number", 2),
+        ("musicbrainz_albumid", "a766da8b-8336-47aa-a3ee-371cc41ccc75"),
+        ("mbid", "bd21ac48-46d8-4e78-925f-d9cc2a294656"),
+        ("musicbrainz_artistid", "013c8e5b-d72a-4cd3-8dee-6c64d6125823"),
+        (
+            "musicbrainz_albumartistid",
+            "013c8e5b-d72a-4cd3-8dee-6c64d6125823;5b4d7d2d-36df-4b38-95e3-a964234f520f",
+        ),
+        ("license", "Dummy license: http://creativecommons.org/licenses/by-sa/4.0/"),
+        ("copyright", "Someone"),
+        ("genre", "Dubstep"),
+    ],
+)
+def test_can_get_metadata_from_m4a_file(field, value):
+    path = os.path.join(DATA_DIR, "test.m4a")
+    data = metadata.Metadata(path)
+
+    assert data.get(field) == value
+
+
 def test_can_get_metadata_from_flac_file_not_crash_if_empty():
     path = os.path.join(DATA_DIR, "sample.flac")
     data = metadata.Metadata(path)
diff --git a/changes/changelog.d/661.enhancement b/changes/changelog.d/661.enhancement
new file mode 100644
index 0000000000000000000000000000000000000000..38553fbfa260fdf86062b705ecf06b2f77c221e4
--- /dev/null
+++ b/changes/changelog.d/661.enhancement
@@ -0,0 +1 @@
+Support for M4A/AAC files (#661)
diff --git a/front/src/components/library/FileUpload.vue b/front/src/components/library/FileUpload.vue
index 025eab930a919ec0dd4e92ce9ad80d5857ca4082..d88efd5ab0b92acf3f0ba17fec90d8cbbdc1b605 100644
--- a/front/src/components/library/FileUpload.vue
+++ b/front/src/components/library/FileUpload.vue
@@ -158,7 +158,7 @@ export default {
       currentTab: "summary",
       uploadUrl: this.$store.getters['instance/absoluteUrl']("/api/v1/uploads/"),
       importReference,
-      supportedExtensions: ["flac", "ogg", "mp3", "opus"],
+      supportedExtensions: ["flac", "ogg", "mp3", "opus", "aac", "m4a"],
       isLoadingQuota: false,
       quotaStatus: null,
       uploads: {