diff --git a/doc/APIchanges b/doc/APIchanges
index eae92c52ee3b4e6fdb053047c5f5c611311eb7d2..8f6cdca467441f4794705e263840646446826c2a 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -13,6 +13,10 @@ libavutil:     2015-08-28
 
 API changes, most recent first:
 
+2016-xx-xx - xxxxxxx - lavf 57.7.0 - avio.h
+  Add AVIODataMarkerType, write_data_type, ignore_boundary_point and
+  avio_write_marker.
+
 2016-xx-xx - xxxxxxx - lavu 55.12.0 - opt.h
   Add av_stereo3d_type_name() and av_stereo3d_from_name().
 
diff --git a/libavformat/avio.h b/libavformat/avio.h
index d60a5977c64060224627a0a982cd3a8ae40f9b96..4bd5cb134a279ff634c08a091c3bf10666357e8f 100644
--- a/libavformat/avio.h
+++ b/libavformat/avio.h
@@ -53,6 +53,42 @@ typedef struct AVIOInterruptCB {
     void *opaque;
 } AVIOInterruptCB;
 
+/**
+ * Different data types that can be returned via the AVIO
+ * write_data_type callback.
+ */
+enum AVIODataMarkerType {
+    /**
+     * Header data; this needs to be present for the stream to be decodeable.
+     */
+    AVIO_DATA_MARKER_HEADER,
+    /**
+     * A point in the output bytestream where a decoder can start decoding
+     * (i.e. a keyframe). A demuxer/decoder given the data flagged with
+     * AVIO_DATA_MARKER_HEADER, followed by any AVIO_DATA_MARKER_SYNC_POINT,
+     * should give decodeable results.
+     */
+    AVIO_DATA_MARKER_SYNC_POINT,
+    /**
+     * A point in the output bytestream where a demuxer can start parsing
+     * (for non self synchronizing bytestream formats). That is, any
+     * non-keyframe packet start point.
+     */
+    AVIO_DATA_MARKER_BOUNDARY_POINT,
+    /**
+     * This is any, unlabelled data. It can either be a muxer not marking
+     * any positions at all, it can be an actual boundary/sync point
+     * that the muxer chooses not to mark, or a later part of a packet/fragment
+     * that is cut into multiple write callbacks due to limited IO buffer size.
+     */
+    AVIO_DATA_MARKER_UNKNOWN,
+    /**
+     * Trailer data, which doesn't contain actual content, but only for
+     * finalizing the output file.
+     */
+    AVIO_DATA_MARKER_TRAILER
+};
+
 /**
  * Bytestream IO Context.
  * New fields can be added to the end with minor version bumps.
@@ -115,6 +151,24 @@ typedef struct AVIOContext {
      * A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
      */
     int seekable;
+
+    /**
+     * A callback that is used instead of write_packet.
+     */
+    int (*write_data_type)(void *opaque, uint8_t *buf, int buf_size,
+                           enum AVIODataMarkerType type, int64_t time);
+    /**
+     * If set, don't call write_data_type separately for AVIO_DATA_MARKER_BOUNDARY_POINT,
+     * but ignore them and treat them as AVIO_DATA_MARKER_UNKNOWN (to avoid needlessly
+     * small chunks of data returned from the callback).
+     */
+    int ignore_boundary_point;
+
+    /**
+     * Internal, not meant to be used from outside of AVIOContext.
+     */
+    enum AVIODataMarkerType current_type;
+    int64_t last_time;
 } AVIOContext;
 
 /**
@@ -192,6 +246,18 @@ int avio_put_str16le(AVIOContext *s, const char *str);
  */
 int avio_put_str16be(AVIOContext *s, const char *str);
 
+/**
+ * Mark the written bytestream as a specific type.
+ *
+ * Zero-length ranges are omitted from the output.
+ *
+ * @param time the stream time the current bytestream pos corresponds to
+ *             (in AV_TIME_BASE units), or AV_NOPTS_VALUE if unknown or not
+ *             applicable
+ * @param type the kind of data written starting at the current pos
+ */
+void avio_write_marker(AVIOContext *s, int64_t time, enum AVIODataMarkerType type);
+
 /**
  * ORing this as the "whence" parameter to a seek function causes it to
  * return the filesize without seeking anywhere. Supporting this is optional.
diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
index 29fccbea83b3b96f13374002ae16b1138ffb6929..706cf5dd7f7739957b8c23fdaf7b6b39bd8eba85 100644
--- a/libavformat/aviobuf.c
+++ b/libavformat/aviobuf.c
@@ -140,6 +140,11 @@ int ffio_init_context(AVIOContext *s,
     s->read_pause = NULL;
     s->read_seek  = NULL;
 
+    s->write_data_type       = NULL;
+    s->ignore_boundary_point = 0;
+    s->current_type          = AVIO_DATA_MARKER_UNKNOWN;
+    s->last_time             = AV_NOPTS_VALUE;
+
     return 0;
 }
 
@@ -163,13 +168,25 @@ AVIOContext *avio_alloc_context(
 static void flush_buffer(AVIOContext *s)
 {
     if (s->buf_ptr > s->buffer) {
-        if (s->write_packet && !s->error) {
-            int ret = s->write_packet(s->opaque, s->buffer,
+        if (!s->error) {
+            int ret = 0;
+            if (s->write_data_type)
+                ret = s->write_data_type(s->opaque, s->buffer,
+                                         s->buf_ptr - s->buffer,
+                                         s->current_type,
+                                         s->last_time);
+            else if (s->write_packet)
+                ret = s->write_packet(s->opaque, s->buffer,
                                       s->buf_ptr - s->buffer);
             if (ret < 0) {
                 s->error = ret;
             }
         }
+        if (s->current_type == AVIO_DATA_MARKER_SYNC_POINT ||
+            s->current_type == AVIO_DATA_MARKER_BOUNDARY_POINT) {
+            s->current_type = AVIO_DATA_MARKER_UNKNOWN;
+        }
+        s->last_time = AV_NOPTS_VALUE;
         if (s->update_checksum) {
             s->checksum     = s->update_checksum(s->checksum, s->checksum_ptr,
                                                  s->buf_ptr - s->checksum_ptr);
@@ -402,6 +419,37 @@ void avio_wb24(AVIOContext *s, unsigned int val)
     avio_w8(s, val);
 }
 
+void avio_write_marker(AVIOContext *s, int64_t time, enum AVIODataMarkerType type)
+{
+    if (!s->write_data_type)
+        return;
+    // If ignoring boundary points, just treat it as unknown
+    if (type == AVIO_DATA_MARKER_BOUNDARY_POINT && s->ignore_boundary_point)
+        type = AVIO_DATA_MARKER_UNKNOWN;
+    // Avoid unnecessary flushes if we are already in non-header/trailer
+    // data and setting the type to unknown
+    if (type == AVIO_DATA_MARKER_UNKNOWN &&
+        (s->current_type != AVIO_DATA_MARKER_HEADER &&
+         s->current_type != AVIO_DATA_MARKER_TRAILER))
+        return;
+
+    switch (type) {
+    case AVIO_DATA_MARKER_HEADER:
+    case AVIO_DATA_MARKER_TRAILER:
+        // For header/trailer, ignore a new marker of the same type;
+        // consecutive header/trailer markers can be merged.
+        if (type == s->current_type)
+            return;
+        break;
+    }
+
+    // If we've reached here, we have a new, noteworthy marker.
+    // Flush the previous data and mark the start of the new data.
+    avio_flush(s);
+    s->current_type = type;
+    s->last_time = time;
+}
+
 /* Input stream */
 
 static void fill_buffer(AVIOContext *s)
diff --git a/libavformat/mux.c b/libavformat/mux.c
index 0761a93b6d103619791b39c68c83aa13308ac0be..49fe65cf98436c0fa879a6a35a1ec5f9bccdaf35 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -256,11 +256,15 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options)
     if (ret = init_muxer(s, options))
         return ret;
 
+    if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
+        avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
     if (s->oformat->write_header) {
         ret = s->oformat->write_header(s);
         if (ret < 0)
             return ret;
     }
+    if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
+        avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_UNKNOWN);
 
     if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO) {
         if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) {
@@ -704,6 +708,8 @@ int av_write_trailer(AVFormatContext *s)
             goto fail;
     }
 
+    if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
+        avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
     if (s->oformat->write_trailer)
         ret = s->oformat->write_trailer(s);
 
diff --git a/libavformat/version.h b/libavformat/version.h
index a50e443c766499ce002c2a21b87cfab525b485e9..b2a1e054bf5e92e674d309dbf99d9625c61e842f 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -30,7 +30,7 @@
 #include "libavutil/version.h"
 
 #define LIBAVFORMAT_VERSION_MAJOR 57
-#define LIBAVFORMAT_VERSION_MINOR  6
+#define LIBAVFORMAT_VERSION_MINOR  7
 #define LIBAVFORMAT_VERSION_MICRO  0
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \