diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 3338f46e268a823bc945950999899f35ec69a22d..39d4e44a449a3355f02c9cb07344252761869ffe 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -3074,7 +3074,9 @@ static int mov_write_header(AVFormatContext *s)
         }
     }
 
-    mov->tracks = av_mallocz(mov->nb_streams * sizeof(*mov->tracks));
+    // Reserve an extra stream for chapters for the case where chapters
+    // are written in the trailer
+    mov->tracks = av_mallocz((mov->nb_streams + 1) * sizeof(*mov->tracks));
     if (!mov->tracks)
         return AVERROR(ENOMEM);
 
@@ -3212,8 +3214,19 @@ static int mov_write_trailer(AVFormatContext *s)
     AVIOContext *pb = s->pb;
     int res = 0;
     int i;
+    int64_t moov_pos;
+
+    // If there were no chapters when the header was written, but there
+    // are chapters now, write them in the trailer.  This only works
+    // when we are not doing fragments.
+    if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
+        if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) {
+            mov->chapter_track = mov->nb_streams++;
+            mov_create_chapter_track(s, mov->chapter_track);
+        }
+    }
 
-    int64_t moov_pos = avio_tell(pb);
+    moov_pos = avio_tell(pb);
 
     if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
         /* Write size of mdat tag */