diff --git a/libavformat/ac4enc.c b/libavformat/ac4enc.c
index aefbfc2684..02b8d4d976 100644
--- a/libavformat/ac4enc.c
+++ b/libavformat/ac4enc.c
@@ -35,7 +35,7 @@ static int ac4_init(AVFormatContext *s)
 {
     AVCodecParameters *par = s->streams[0]->codecpar;
 
-    if (s->nb_streams != 1 || par->codec_id != AV_CODEC_ID_AC4) {
+    if (par->codec_id != AV_CODEC_ID_AC4) {
         av_log(s, AV_LOG_ERROR, "Only one AC-4 stream can be muxed by the AC-4 muxer\n");
         return AVERROR(EINVAL);
     }
@@ -95,6 +95,8 @@ const FFOutputFormat ff_ac4_muxer = {
     .priv_data_size    = sizeof(AC4Context),
     .p.audio_codec     = AV_CODEC_ID_AC4,
     .p.video_codec     = AV_CODEC_ID_NONE,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .init              = ac4_init,
     .write_packet      = ac4_write_packet,
     .p.priv_class      = &ac4_muxer_class,
diff --git a/libavformat/aeaenc.c b/libavformat/aeaenc.c
index 495e98c6a2..3303d108a5 100644
--- a/libavformat/aeaenc.c
+++ b/libavformat/aeaenc.c
@@ -29,14 +29,8 @@ static int aea_write_header(AVFormatContext *s)
 {
     const AVDictionaryEntry *title_entry;
     size_t title_length = 0;
-    AVStream *st;
-
-    if (s->nb_streams > 1) {
-        av_log(s, AV_LOG_ERROR, "Got more than one stream to encode. This is not supported.\n");
-        return AVERROR(EINVAL);
-    }
+    AVStream *st = s->streams[0];
 
-    st = s->streams[0];
     if (st->codecpar->ch_layout.nb_channels != 1 && st->codecpar->ch_layout.nb_channels != 2) {
         av_log(s, AV_LOG_ERROR, "Only maximum 2 channels are supported in the audio"
                " stream, %d channels were found.\n", st->codecpar->ch_layout.nb_channels);
@@ -108,7 +102,10 @@ const FFOutputFormat ff_aea_muxer = {
     .p.long_name      = NULL_IF_CONFIG_SMALL("MD STUDIO audio"),
     .p.extensions     = "aea",
     .p.audio_codec    = AV_CODEC_ID_ATRAC1,
+    .p.video_codec    = AV_CODEC_ID_NONE,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
 
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_header     = aea_write_header,
     .write_packet     = ff_raw_write_packet,
     .write_trailer    = aea_write_trailer,
diff --git a/libavformat/alp.c b/libavformat/alp.c
index 3db256cd05..9d507cb310 100644
--- a/libavformat/alp.c
+++ b/libavformat/alp.c
@@ -189,11 +189,6 @@ static int alp_write_init(AVFormatContext *s)
             alp->type = ALP_TYPE_TUN;
     }
 
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "Too many streams\n");
-        return AVERROR(EINVAL);
-    }
-
     par = s->streams[0]->codecpar;
 
     if (par->codec_id != AV_CODEC_ID_ADPCM_IMA_ALP) {
@@ -298,7 +293,9 @@ const FFOutputFormat ff_alp_muxer = {
     .p.extensions   = "tun,pcm",
     .p.audio_codec  = AV_CODEC_ID_ADPCM_IMA_ALP,
     .p.video_codec  = AV_CODEC_ID_NONE,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
     .p.priv_class   = &alp_muxer_class,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .init           = alp_write_init,
     .write_header   = alp_write_header,
     .write_packet   = ff_raw_write_packet,
diff --git a/libavformat/apm.c b/libavformat/apm.c
index bcde82d958..89401dcf5b 100644
--- a/libavformat/apm.c
+++ b/libavformat/apm.c
@@ -215,14 +215,7 @@ const FFInputFormat ff_apm_demuxer = {
 #if CONFIG_APM_MUXER
 static int apm_write_init(AVFormatContext *s)
 {
-    AVCodecParameters *par;
-
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "APM files have exactly one stream\n");
-        return AVERROR(EINVAL);
-    }
-
-    par = s->streams[0]->codecpar;
+    AVCodecParameters *par = s->streams[0]->codecpar;
 
     if (par->codec_id != AV_CODEC_ID_ADPCM_IMA_APM) {
         av_log(s, AV_LOG_ERROR, "%s codec not supported\n",
@@ -311,6 +304,8 @@ const FFOutputFormat ff_apm_muxer = {
     .p.extensions   = "apm",
     .p.audio_codec  = AV_CODEC_ID_ADPCM_IMA_APM,
     .p.video_codec  = AV_CODEC_ID_NONE,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .init           = apm_write_init,
     .write_header   = apm_write_header,
     .write_packet   = ff_raw_write_packet,
diff --git a/libavformat/apngenc.c b/libavformat/apngenc.c
index a0af916f14..79b0dbf0f7 100644
--- a/libavformat/apngenc.c
+++ b/libavformat/apngenc.c
@@ -84,9 +84,7 @@ static int apng_write_header(AVFormatContext *format_context)
     APNGMuxContext *apng = format_context->priv_data;
     AVCodecParameters *par = format_context->streams[0]->codecpar;
 
-    if (format_context->nb_streams != 1 ||
-        format_context->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
-        format_context->streams[0]->codecpar->codec_id   != AV_CODEC_ID_APNG) {
+    if (format_context->streams[0]->codecpar->codec_id   != AV_CODEC_ID_APNG) {
         av_log(format_context, AV_LOG_ERROR,
                "APNG muxer supports only a single video APNG stream.\n");
         return AVERROR(EINVAL);
@@ -315,6 +313,8 @@ const FFOutputFormat ff_apng_muxer = {
     .priv_data_size = sizeof(APNGMuxContext),
     .p.audio_codec  = AV_CODEC_ID_NONE,
     .p.video_codec  = AV_CODEC_ID_APNG,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_header   = apng_write_header,
     .write_packet   = apng_write_packet,
     .write_trailer  = apng_write_trailer,
diff --git a/libavformat/argo_asf.c b/libavformat/argo_asf.c
index 0e1eae24fb..28e3844394 100644
--- a/libavformat/argo_asf.c
+++ b/libavformat/argo_asf.c
@@ -288,14 +288,7 @@ const FFInputFormat ff_argo_asf_demuxer = {
 static int argo_asf_write_init(AVFormatContext *s)
 {
     ArgoASFMuxContext *ctx = s->priv_data;
-    const AVCodecParameters *par;
-
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "ASF files have exactly one stream\n");
-        return AVERROR(EINVAL);
-    }
-
-    par = s->streams[0]->codecpar;
+    const AVCodecParameters *par = s->streams[0]->codecpar;
 
     if (par->codec_id != AV_CODEC_ID_ADPCM_ARGO) {
         av_log(s, AV_LOG_ERROR, "%s codec not supported\n",
@@ -481,7 +474,9 @@ const FFOutputFormat ff_argo_asf_muxer = {
      */
     .p.audio_codec  = AV_CODEC_ID_ADPCM_ARGO,
     .p.video_codec  = AV_CODEC_ID_NONE,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
     .p.priv_class   = &argo_asf_muxer_class,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .init           = argo_asf_write_init,
     .write_header   = argo_asf_write_header,
     .write_packet   = argo_asf_write_packet,
diff --git a/libavformat/argo_cvg.c b/libavformat/argo_cvg.c
index 0cf0bf3e9a..aacc34daeb 100644
--- a/libavformat/argo_cvg.c
+++ b/libavformat/argo_cvg.c
@@ -269,14 +269,7 @@ const FFInputFormat ff_argo_cvg_demuxer = {
 static int argo_cvg_write_init(AVFormatContext *s)
 {
     ArgoCVGMuxContext *ctx = s->priv_data;
-    const AVCodecParameters *par;
-
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "CVG files have exactly one stream\n");
-        return AVERROR(EINVAL);
-    }
-
-    par = s->streams[0]->codecpar;
+    const AVCodecParameters *par = s->streams[0]->codecpar;
 
     if (par->codec_id != AV_CODEC_ID_ADPCM_PSX) {
         av_log(s, AV_LOG_ERROR, "%s codec not supported\n",
@@ -408,7 +401,9 @@ const FFOutputFormat ff_argo_cvg_muxer = {
     .p.extensions   = "cvg",
     .p.audio_codec  = AV_CODEC_ID_ADPCM_PSX,
     .p.video_codec  = AV_CODEC_ID_NONE,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
     .p.priv_class   = &argo_cvg_muxer_class,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .init           = argo_cvg_write_init,
     .write_header   = argo_cvg_write_header,
     .write_packet   = argo_cvg_write_packet,
diff --git a/libavformat/assenc.c b/libavformat/assenc.c
index dad0d81ca8..c23c77acda 100644
--- a/libavformat/assenc.c
+++ b/libavformat/assenc.c
@@ -50,7 +50,7 @@ static int write_header(AVFormatContext *s)
     ASSContext *ass = s->priv_data;
     AVCodecParameters *par = s->streams[0]->codecpar;
 
-    if (s->nb_streams != 1 || par->codec_id != AV_CODEC_ID_ASS) {
+    if (par->codec_id != AV_CODEC_ID_ASS) {
         av_log(s, AV_LOG_ERROR, "Exactly one ASS/SSA stream is needed.\n");
         return AVERROR(EINVAL);
     }
@@ -237,8 +237,11 @@ const FFOutputFormat ff_ass_muxer = {
     .p.long_name      = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) subtitle"),
     .p.mime_type      = "text/x-ass",
     .p.extensions     = "ass,ssa",
+    .p.audio_codec    = AV_CODEC_ID_NONE,
+    .p.video_codec    = AV_CODEC_ID_NONE,
     .p.subtitle_codec = AV_CODEC_ID_ASS,
     .p.flags          = AVFMT_GLOBALHEADER | AVFMT_NOTIMESTAMPS | AVFMT_TS_NONSTRICT,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .p.priv_class     = &ass_class,
     .priv_data_size = sizeof(ASSContext),
     .write_header   = write_header,
diff --git a/libavformat/astenc.c b/libavformat/astenc.c
index c6b02e3848..1fa06a2da8 100644
--- a/libavformat/astenc.c
+++ b/libavformat/astenc.c
@@ -49,16 +49,9 @@ static int ast_write_header(AVFormatContext *s)
 {
     ASTMuxContext *ast = s->priv_data;
     AVIOContext *pb = s->pb;
-    AVCodecParameters *par;
+    AVCodecParameters *par = s->streams[0]->codecpar;
     unsigned int codec_tag;
 
-    if (s->nb_streams == 1) {
-        par = s->streams[0]->codecpar;
-    } else {
-        av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
-        return AVERROR(EINVAL);
-    }
-
     if (par->codec_id == AV_CODEC_ID_ADPCM_AFC) {
         av_log(s, AV_LOG_ERROR, "muxing ADPCM AFC is not implemented\n");
         return AVERROR_PATCHWELCOME;
@@ -204,6 +197,8 @@ const FFOutputFormat ff_ast_muxer = {
     .priv_data_size    = sizeof(ASTMuxContext),
     .p.audio_codec     = AV_CODEC_ID_PCM_S16BE_PLANAR,
     .p.video_codec     = AV_CODEC_ID_NONE,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_header      = ast_write_header,
     .write_packet      = ast_write_packet,
     .write_trailer     = ast_write_trailer,
diff --git a/libavformat/au.c b/libavformat/au.c
index da1fc79f0d..98f1a5b507 100644
--- a/libavformat/au.c
+++ b/libavformat/au.c
@@ -291,11 +291,6 @@ static int au_write_header(AVFormatContext *s)
     AVCodecParameters *par = s->streams[0]->codecpar;
     AVBPrint annotations;
 
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
-        return AVERROR(EINVAL);
-    }
-
     par->codec_tag = ff_codec_get_tag(codec_au_tags, par->codec_id);
     if (!par->codec_tag) {
         av_log(s, AV_LOG_ERROR, "unsupported codec\n");
@@ -346,7 +341,9 @@ const FFOutputFormat ff_au_muxer = {
     .p.codec_tag    = au_codec_tags,
     .p.audio_codec  = AV_CODEC_ID_PCM_S16BE,
     .p.video_codec  = AV_CODEC_ID_NONE,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
     .p.flags        = AVFMT_NOTIMESTAMPS,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .priv_data_size = sizeof(AUContext),
     .write_header  = au_write_header,
     .write_packet  = ff_raw_write_packet,
diff --git a/libavformat/cafenc.c b/libavformat/cafenc.c
index 67be59806c..426bc05209 100644
--- a/libavformat/cafenc.c
+++ b/libavformat/cafenc.c
@@ -118,11 +118,6 @@ static int caf_write_header(AVFormatContext *s)
     int64_t chunk_size = 0;
     int frame_size = par->frame_size, sample_rate = par->sample_rate;
 
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "CAF files have exactly one stream\n");
-        return AVERROR(EINVAL);
-    }
-
     switch (par->codec_id) {
     case AV_CODEC_ID_AAC:
         av_log(s, AV_LOG_ERROR, "muxing codec currently unsupported\n");
@@ -284,6 +279,8 @@ const FFOutputFormat ff_caf_muxer = {
     .priv_data_size = sizeof(CAFContext),
     .p.audio_codec  = AV_CODEC_ID_PCM_S16BE,
     .p.video_codec  = AV_CODEC_ID_NONE,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_header   = caf_write_header,
     .write_packet   = caf_write_packet,
     .write_trailer  = caf_write_trailer,
diff --git a/libavformat/chromaprint.c b/libavformat/chromaprint.c
index 3229e9160d..62264d6a4b 100644
--- a/libavformat/chromaprint.c
+++ b/libavformat/chromaprint.c
@@ -85,11 +85,6 @@ static int write_header(AVFormatContext *s)
 #endif
     }
 
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "Only one stream is supported\n");
-        return AVERROR(EINVAL);
-    }
-
     st = s->streams[0];
 
     if (st->codecpar->ch_layout.nb_channels > 2) {
@@ -182,6 +177,9 @@ const FFOutputFormat ff_chromaprint_muxer = {
     .p.long_name       = NULL_IF_CONFIG_SMALL("Chromaprint"),
     .priv_data_size    = sizeof(ChromaprintMuxContext),
     .p.audio_codec     = AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE),
+    .p.video_codec     = AV_CODEC_ID_NONE,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_header      = write_header,
     .write_packet      = write_packet,
     .write_trailer     = write_trailer,
diff --git a/libavformat/codec2.c b/libavformat/codec2.c
index 9ed57af0a8..e49408e0fb 100644
--- a/libavformat/codec2.c
+++ b/libavformat/codec2.c
@@ -216,7 +216,7 @@ static int codec2_write_header(AVFormatContext *s)
 {
     AVStream *st;
 
-    if (s->nb_streams != 1 || s->streams[0]->codecpar->codec_id != AV_CODEC_ID_CODEC2) {
+    if (s->streams[0]->codecpar->codec_id != AV_CODEC_ID_CODEC2) {
         av_log(s, AV_LOG_ERROR, ".c2 files must have exactly one codec2 stream\n");
         return AVERROR(EINVAL);
     }
@@ -317,7 +317,9 @@ const FFOutputFormat ff_codec2_muxer = {
     .p.extensions   = "c2",
     .p.audio_codec  = AV_CODEC_ID_CODEC2,
     .p.video_codec  = AV_CODEC_ID_NONE,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
     .p.flags        = AVFMT_NOTIMESTAMPS,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_header   = codec2_write_header,
     .write_packet   = ff_raw_write_packet,
 };
diff --git a/libavformat/gif.c b/libavformat/gif.c
index 568867cc5d..fe45637814 100644
--- a/libavformat/gif.c
+++ b/libavformat/gif.c
@@ -42,9 +42,7 @@ typedef struct GIFContext {
 
 static int gif_write_header(AVFormatContext *s)
 {
-    if (s->nb_streams != 1 ||
-        s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
-        s->streams[0]->codecpar->codec_id   != AV_CODEC_ID_GIF) {
+    if (s->streams[0]->codecpar->codec_id   != AV_CODEC_ID_GIF) {
         av_log(s, AV_LOG_ERROR,
                "GIF muxer supports only a single video GIF stream.\n");
         return AVERROR(EINVAL);
@@ -213,6 +211,8 @@ const FFOutputFormat ff_gif_muxer = {
     .priv_data_size = sizeof(GIFContext),
     .p.audio_codec  = AV_CODEC_ID_NONE,
     .p.video_codec  = AV_CODEC_ID_GIF,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_header   = gif_write_header,
     .write_packet   = gif_write_packet,
     .write_trailer  = gif_write_trailer,
diff --git a/libavformat/ilbc.c b/libavformat/ilbc.c
index bb98d0e62a..2e102a4be7 100644
--- a/libavformat/ilbc.c
+++ b/libavformat/ilbc.c
@@ -33,13 +33,7 @@ static const char mode30_header[] = "#!iLBC30\n";
 static int ilbc_write_header(AVFormatContext *s)
 {
     AVIOContext *pb = s->pb;
-    AVCodecParameters *par;
-
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "Unsupported number of streams\n");
-        return AVERROR(EINVAL);
-    }
-    par = s->streams[0]->codecpar;
+    AVCodecParameters *par = s->streams[0]->codecpar;
 
     if (par->codec_id != AV_CODEC_ID_ILBC) {
         av_log(s, AV_LOG_ERROR, "Unsupported codec\n");
@@ -127,8 +121,11 @@ const FFOutputFormat ff_ilbc_muxer = {
     .p.long_name    = NULL_IF_CONFIG_SMALL("iLBC storage"),
     .p.mime_type    = "audio/iLBC",
     .p.extensions   = "lbc",
+    .p.video_codec    = AV_CODEC_ID_NONE,
     .p.audio_codec  = AV_CODEC_ID_ILBC,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
     .p.flags        = AVFMT_NOTIMESTAMPS,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_header = ilbc_write_header,
     .write_packet = ff_raw_write_packet,
 };
diff --git a/libavformat/ircamenc.c b/libavformat/ircamenc.c
index ceeab2b305..7600d9a8a9 100644
--- a/libavformat/ircamenc.c
+++ b/libavformat/ircamenc.c
@@ -32,11 +32,6 @@ static int ircam_write_header(AVFormatContext *s)
     AVCodecParameters *par = s->streams[0]->codecpar;
     uint32_t tag;
 
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
-        return AVERROR(EINVAL);
-    }
-
     tag = ff_codec_get_tag(ff_codec_ircam_le_tags, par->codec_id);
     if (!tag) {
         av_log(s, AV_LOG_ERROR, "unsupported codec\n");
@@ -57,6 +52,8 @@ const FFOutputFormat ff_ircam_muxer = {
     .p.long_name    = NULL_IF_CONFIG_SMALL("Berkeley/IRCAM/CARL Sound Format"),
     .p.audio_codec  = AV_CODEC_ID_PCM_S16LE,
     .p.video_codec  = AV_CODEC_ID_NONE,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_header   = ircam_write_header,
     .write_packet   = ff_raw_write_packet,
     .p.codec_tag    = (const AVCodecTag *const []){ ff_codec_ircam_le_tags, 0 },
diff --git a/libavformat/ivfenc.c b/libavformat/ivfenc.c
index 88399099d4..09782eecd6 100644
--- a/libavformat/ivfenc.c
+++ b/libavformat/ivfenc.c
@@ -29,15 +29,9 @@ typedef struct IVFEncContext {
 
 static int ivf_init(AVFormatContext *s)
 {
-    AVCodecParameters *par;
+    AVCodecParameters *par = s->streams[0]->codecpar;
 
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "Format supports only exactly one video stream\n");
-        return AVERROR(EINVAL);
-    }
-    par = s->streams[0]->codecpar;
-    if (par->codec_type != AVMEDIA_TYPE_VIDEO ||
-        !(par->codec_id == AV_CODEC_ID_AV1 ||
+    if (!(par->codec_id == AV_CODEC_ID_AV1 ||
           par->codec_id == AV_CODEC_ID_VP8 ||
           par->codec_id == AV_CODEC_ID_VP9)) {
         av_log(s, AV_LOG_ERROR, "Currently only VP8, VP9 and AV1 are supported!\n");
@@ -125,7 +119,9 @@ const FFOutputFormat ff_ivf_muxer = {
     .p.extensions   = "ivf",
     .p.audio_codec  = AV_CODEC_ID_NONE,
     .p.video_codec  = AV_CODEC_ID_VP8,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
     .p.codec_tag    = (const AVCodecTag* const []){ codec_ivf_tags, 0 },
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .priv_data_size = sizeof(IVFEncContext),
     .init         = ivf_init,
     .write_header = ivf_write_header,
diff --git a/libavformat/kvag.c b/libavformat/kvag.c
index bea1dda3e5..2053f4730d 100644
--- a/libavformat/kvag.c
+++ b/libavformat/kvag.c
@@ -129,14 +129,7 @@ const FFInputFormat ff_kvag_demuxer = {
 #if CONFIG_KVAG_MUXER
 static int kvag_write_init(AVFormatContext *s)
 {
-    AVCodecParameters *par;
-
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "KVAG files have exactly one stream\n");
-        return AVERROR(EINVAL);
-    }
-
-    par = s->streams[0]->codecpar;
+    AVCodecParameters *par = s->streams[0]->codecpar;
 
     if (par->codec_id != AV_CODEC_ID_ADPCM_IMA_SSI) {
         av_log(s, AV_LOG_ERROR, "%s codec not supported\n",
@@ -196,6 +189,8 @@ const FFOutputFormat ff_kvag_muxer = {
     .p.extensions   = "vag",
     .p.audio_codec  = AV_CODEC_ID_ADPCM_IMA_SSI,
     .p.video_codec  = AV_CODEC_ID_NONE,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .init           = kvag_write_init,
     .write_header   = kvag_write_header,
     .write_packet   = ff_raw_write_packet,
diff --git a/libavformat/lrcenc.c b/libavformat/lrcenc.c
index d66be9a8fa..15c31d33b3 100644
--- a/libavformat/lrcenc.c
+++ b/libavformat/lrcenc.c
@@ -37,12 +37,6 @@ static int lrc_write_header(AVFormatContext *s)
 {
     const AVDictionaryEntry *metadata_item;
 
-    if(s->nb_streams != 1 ||
-       s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
-        av_log(s, AV_LOG_ERROR,
-               "LRC supports only a single subtitle stream.\n");
-        return AVERROR(EINVAL);
-    }
     if(s->streams[0]->codecpar->codec_id != AV_CODEC_ID_SUBRIP &&
        s->streams[0]->codecpar->codec_id != AV_CODEC_ID_TEXT) {
         av_log(s, AV_LOG_ERROR, "Unsupported subtitle codec: %s\n",
@@ -131,7 +125,10 @@ const FFOutputFormat ff_lrc_muxer = {
     .p.extensions     = "lrc",
     .p.flags          = AVFMT_VARIABLE_FPS | AVFMT_GLOBALHEADER |
                         AVFMT_TS_NEGATIVE | AVFMT_TS_NONSTRICT,
+    .p.video_codec    = AV_CODEC_ID_NONE,
+    .p.audio_codec    = AV_CODEC_ID_NONE,
     .p.subtitle_codec = AV_CODEC_ID_SUBRIP,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .priv_data_size = 0,
     .write_header   = lrc_write_header,
     .write_packet   = lrc_write_packet,
diff --git a/libavformat/microdvdenc.c b/libavformat/microdvdenc.c
index 950309981b..b9cadb8be4 100644
--- a/libavformat/microdvdenc.c
+++ b/libavformat/microdvdenc.c
@@ -29,7 +29,7 @@ static int microdvd_write_header(struct AVFormatContext *s)
     AVCodecParameters *par = s->streams[0]->codecpar;
     AVRational framerate = s->streams[0]->avg_frame_rate;
 
-    if (s->nb_streams != 1 || par->codec_id != AV_CODEC_ID_MICRODVD) {
+    if (par->codec_id != AV_CODEC_ID_MICRODVD) {
         av_log(s, AV_LOG_ERROR, "Exactly one MicroDVD stream is needed.\n");
         return -1;
     }
@@ -62,7 +62,10 @@ const FFOutputFormat ff_microdvd_muxer = {
     .p.mime_type      = "text/x-microdvd",
     .p.extensions     = "sub",
     .p.flags          = AVFMT_NOTIMESTAMPS,
+    .p.video_codec    = AV_CODEC_ID_NONE,
+    .p.audio_codec    = AV_CODEC_ID_NONE,
     .p.subtitle_codec = AV_CODEC_ID_MICRODVD,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_header   = microdvd_write_header,
     .write_packet   = microdvd_write_packet,
 };
diff --git a/libavformat/mux.c b/libavformat/mux.c
index a2cae97397..134c2875b6 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -188,6 +188,12 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options)
     AVDictionary *tmp = NULL;
     const FFOutputFormat *of = ffofmt(s->oformat);
     AVDictionaryEntry *e;
+    static const unsigned default_codec_offsets[] = {
+        [AVMEDIA_TYPE_VIDEO]    = offsetof(AVOutputFormat, video_codec),
+        [AVMEDIA_TYPE_AUDIO]    = offsetof(AVOutputFormat, audio_codec),
+        [AVMEDIA_TYPE_SUBTITLE] = offsetof(AVOutputFormat, subtitle_codec),
+    };
+    unsigned nb_type[FF_ARRAY_ELEMS(default_codec_offsets)] = { 0 };
     int ret = 0;
 
     if (options)
@@ -262,6 +268,23 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options)
             }
             break;
         }
+        if (of->flags_internal & FF_OFMT_FLAG_MAX_ONE_OF_EACH) {
+            enum AVCodecID default_codec_id = AV_CODEC_ID_NONE;
+            unsigned nb;
+            if ((unsigned)par->codec_type < FF_ARRAY_ELEMS(default_codec_offsets)) {
+                nb = ++nb_type[par->codec_type];
+                if (default_codec_offsets[par->codec_type])
+                    default_codec_id = *(const enum AVCodecID*)((const char*)of + default_codec_offsets[par->codec_type]);
+            }
+            if (default_codec_id == AV_CODEC_ID_NONE || nb > 1) {
+                const char *type = av_get_media_type_string(par->codec_type);
+                av_log(s, AV_LOG_ERROR, "%s muxer does not support %s stream of type %s\n",
+                       of->p.name, default_codec_id == AV_CODEC_ID_NONE ? "any" : "more than one",
+                       type ? type : "unknown");
+                ret = AVERROR(EINVAL);
+                goto fail;
+            }
+        }
 
 #if FF_API_AVSTREAM_SIDE_DATA
 FF_DISABLE_DEPRECATION_WARNINGS
diff --git a/libavformat/mux.h b/libavformat/mux.h
index bd3eb53380..71ee5fd06b 100644
--- a/libavformat/mux.h
+++ b/libavformat/mux.h
@@ -36,6 +36,20 @@ struct AVDeviceInfoList;
  * of the return value in case of flushing.
  */
 #define FF_OFMT_FLAG_ALLOW_FLUSH                    (1 << 1)
+/**
+ * If this flag is set, it indicates that for each codec type
+ * whose corresponding default codec (i.e. AVOutputFormat.audio_codec,
+ * AVOutputFormat.video_codec and AVOutputFormat.subtitle_codec)
+ * is set (i.e. != AV_CODEC_ID_NONE) only one stream of this type
+ * can be muxed. It furthermore indicates that no stream with
+ * a codec type that has no default codec or whose default codec
+ * is AV_CODEC_ID_NONE can be muxed.
+ * Both of these restrictions are checked generically before
+ * the actual muxer's init/write_header callbacks.
+ *
+ * This flag is incompatible with FF_OFMT_FLAG_SUPPORT_ATTACHMENTS.
+ */
+#define FF_OFMT_FLAG_MAX_ONE_OF_EACH                (1 << 2)
 
 typedef struct FFOutputFormat {
     /**
diff --git a/libavformat/mux_utils.c b/libavformat/mux_utils.c
index 841a19a3a2..8a0ad4c9aa 100644
--- a/libavformat/mux_utils.c
+++ b/libavformat/mux_utils.c
@@ -44,6 +44,25 @@ int avformat_query_codec(const AVOutputFormat *ofmt, enum AVCodecID codec_id,
                   codec_id == ofmt->audio_codec ||
                   codec_id == ofmt->subtitle_codec))
             return 1;
+        else if (ffofmt(ofmt)->flags_internal & FF_OFMT_FLAG_MAX_ONE_OF_EACH) {
+            enum AVMediaType type = avcodec_get_type(codec_id);
+            switch (type) {
+            case AVMEDIA_TYPE_AUDIO:
+                if (ofmt->audio_codec == AV_CODEC_ID_NONE)
+                    return 0;
+                break;
+            case AVMEDIA_TYPE_VIDEO:
+                if (ofmt->video_codec == AV_CODEC_ID_NONE)
+                    return 0;
+                break;
+            case AVMEDIA_TYPE_SUBTITLE:
+                if (ofmt->subtitle_codec == AV_CODEC_ID_NONE)
+                    return 0;
+                break;
+            default:
+                return 0;
+            }
+        }
     }
     return AVERROR_PATCHWELCOME;
 }
diff --git a/libavformat/rawenc.c b/libavformat/rawenc.c
index f916db13a2..49dc0a9109 100644
--- a/libavformat/rawenc.c
+++ b/libavformat/rawenc.c
@@ -34,28 +34,6 @@ int ff_raw_write_packet(AVFormatContext *s, AVPacket *pkt)
     return 0;
 }
 
-static int force_one_stream(AVFormatContext *s)
-{
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "%s files have exactly one stream\n",
-               s->oformat->name);
-        return AVERROR(EINVAL);
-    }
-    if (   s->oformat->audio_codec != AV_CODEC_ID_NONE
-        && s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) {
-        av_log(s, AV_LOG_ERROR, "%s files have exactly one audio stream\n",
-               s->oformat->name);
-        return AVERROR(EINVAL);
-    }
-    if (   s->oformat->video_codec != AV_CODEC_ID_NONE
-        && s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {
-        av_log(s, AV_LOG_ERROR, "%s files have exactly one video stream\n",
-               s->oformat->name);
-        return AVERROR(EINVAL);
-    }
-    return 0;
-}
-
 /* Note: Do not forget to add new entries to the Makefile as well. */
 
 #if CONFIG_AC3_MUXER
@@ -66,7 +44,8 @@ const FFOutputFormat ff_ac3_muxer = {
     .p.extensions      = "ac3",
     .p.audio_codec     = AV_CODEC_ID_AC3,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -98,7 +77,8 @@ const FFOutputFormat ff_adx_muxer = {
     .p.extensions      = "adx",
     .p.audio_codec     = AV_CODEC_ID_ADPCM_ADX,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .write_trailer     = adx_write_trailer,
     .p.flags           = AVFMT_NOTIMESTAMPS,
@@ -112,7 +92,8 @@ const FFOutputFormat ff_aptx_muxer = {
     .p.extensions      = "aptx",
     .p.audio_codec     = AV_CODEC_ID_APTX,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -125,7 +106,8 @@ const FFOutputFormat ff_aptx_hd_muxer = {
     .p.extensions      = "aptxhd",
     .p.audio_codec     = AV_CODEC_ID_APTX_HD,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -138,7 +120,8 @@ const FFOutputFormat ff_avs2_muxer = {
     .p.extensions      = "avs,avs2",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_AVS2,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -151,7 +134,8 @@ const FFOutputFormat ff_avs3_muxer = {
     .p.extensions      = "avs3",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_AVS3,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -165,7 +149,8 @@ const FFOutputFormat ff_cavsvideo_muxer = {
     .p.extensions      = "cavs",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_CAVS,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -177,7 +162,8 @@ const FFOutputFormat ff_codec2raw_muxer = {
     .p.long_name       = NULL_IF_CONFIG_SMALL("raw codec2 muxer"),
     .p.audio_codec     = AV_CODEC_ID_CODEC2,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -185,6 +171,15 @@ const FFOutputFormat ff_codec2raw_muxer = {
 
 
 #if CONFIG_DATA_MUXER
+static av_cold int force_one_stream(AVFormatContext *s)
+{
+    if (s->nb_streams != 1) {
+        av_log(s, AV_LOG_ERROR, "This muxer supports only one stream.\n");
+        return AVERROR(EINVAL);
+    }
+    return 0;
+}
+
 const FFOutputFormat ff_data_muxer = {
     .p.name            = "data",
     .p.long_name       = NULL_IF_CONFIG_SMALL("raw data"),
@@ -201,7 +196,8 @@ const FFOutputFormat ff_dfpwm_muxer = {
     .p.extensions      = "dfpwm",
     .p.audio_codec     = AV_CODEC_ID_DFPWM,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -214,7 +210,8 @@ const FFOutputFormat ff_dirac_muxer = {
     .p.extensions      = "drc,vc2",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_DIRAC,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -227,7 +224,8 @@ const FFOutputFormat ff_dnxhd_muxer = {
     .p.extensions      = "dnxhd,dnxhr",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_DNXHD,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -241,7 +239,8 @@ const FFOutputFormat ff_dts_muxer = {
     .p.extensions      = "dts",
     .p.audio_codec     = AV_CODEC_ID_DTS,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -255,7 +254,8 @@ const FFOutputFormat ff_eac3_muxer = {
     .p.extensions      = "eac3,ec3",
     .p.audio_codec     = AV_CODEC_ID_EAC3,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -269,7 +269,8 @@ const FFOutputFormat ff_g722_muxer = {
     .p.extensions      = "g722",
     .p.audio_codec     = AV_CODEC_ID_ADPCM_G722,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -283,7 +284,8 @@ const FFOutputFormat ff_g723_1_muxer = {
     .p.extensions      = "tco,rco",
     .p.audio_codec     = AV_CODEC_ID_G723_1,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -295,7 +297,8 @@ const FFOutputFormat ff_g726_muxer = {
     .p.long_name       = NULL_IF_CONFIG_SMALL("raw big-endian G.726 (\"left-justified\")"),
     .p.audio_codec     = AV_CODEC_ID_ADPCM_G726,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -307,7 +310,8 @@ const FFOutputFormat ff_g726le_muxer = {
     .p.long_name       = NULL_IF_CONFIG_SMALL("raw little-endian G.726 (\"right-justified\")"),
     .p.audio_codec     = AV_CODEC_ID_ADPCM_G726LE,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -321,7 +325,8 @@ const FFOutputFormat ff_gsm_muxer = {
     .p.extensions      = "gsm",
     .p.audio_codec     = AV_CODEC_ID_GSM,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -335,7 +340,8 @@ const FFOutputFormat ff_h261_muxer = {
     .p.extensions      = "h261",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_H261,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -349,7 +355,8 @@ const FFOutputFormat ff_h263_muxer = {
     .p.extensions      = "h263",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_H263,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -371,7 +378,8 @@ const FFOutputFormat ff_h264_muxer = {
     .p.extensions      = "h264,264",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_H264,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .check_bitstream   = h264_check_bitstream,
     .p.flags           = AVFMT_NOTIMESTAMPS,
@@ -394,7 +402,8 @@ const FFOutputFormat ff_vvc_muxer = {
     .p.extensions      = "vvc,h266,266",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_VVC,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .check_bitstream   = vvc_check_bitstream,
     .p.flags           = AVFMT_NOTIMESTAMPS,
@@ -417,7 +426,8 @@ const FFOutputFormat ff_hevc_muxer = {
     .p.extensions      = "hevc,h265,265",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_HEVC,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .check_bitstream   = hevc_check_bitstream,
     .p.flags           = AVFMT_NOTIMESTAMPS,
@@ -431,7 +441,8 @@ const FFOutputFormat ff_evc_muxer = {
     .p.extensions      = "evc",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_EVC,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -444,7 +455,8 @@ const FFOutputFormat ff_m4v_muxer = {
     .p.extensions      = "m4v",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_MPEG4,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -458,7 +470,8 @@ const FFOutputFormat ff_mjpeg_muxer = {
     .p.extensions      = "mjpg,mjpeg",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_MJPEG,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -471,7 +484,8 @@ const FFOutputFormat ff_mlp_muxer = {
     .p.extensions      = "mlp",
     .p.audio_codec     = AV_CODEC_ID_MLP,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -485,7 +499,8 @@ const FFOutputFormat ff_mp2_muxer = {
     .p.extensions      = "mp2,m2a,mpa",
     .p.audio_codec     = AV_CODEC_ID_MP2,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -499,7 +514,8 @@ const FFOutputFormat ff_mpeg1video_muxer = {
     .p.extensions      = "mpg,mpeg,m1v",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_MPEG1VIDEO,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -512,7 +528,8 @@ const FFOutputFormat ff_mpeg2video_muxer = {
     .p.extensions      = "m2v",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_MPEG2VIDEO,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -531,7 +548,8 @@ const FFOutputFormat ff_obu_muxer = {
     .p.extensions      = "obu",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_AV1,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .check_bitstream   = obu_check_bitstream,
     .p.flags           = AVFMT_NOTIMESTAMPS,
@@ -545,6 +563,7 @@ const FFOutputFormat ff_rawvideo_muxer = {
     .p.extensions      = "yuv,rgb",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_RAWVIDEO,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -557,7 +576,9 @@ const FFOutputFormat ff_sbc_muxer = {
     .p.mime_type       = "audio/x-sbc",
     .p.extensions      = "sbc,msbc",
     .p.audio_codec     = AV_CODEC_ID_SBC,
-    .init              = force_one_stream,
+    .p.video_codec     = AV_CODEC_ID_NONE,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -570,7 +591,8 @@ const FFOutputFormat ff_truehd_muxer = {
     .p.extensions      = "thd",
     .p.audio_codec     = AV_CODEC_ID_TRUEHD,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
@@ -583,7 +605,8 @@ const FFOutputFormat ff_vc1_muxer = {
     .p.extensions      = "vc1",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_VC1,
-    .init              = force_one_stream,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_packet      = ff_raw_write_packet,
     .p.flags           = AVFMT_NOTIMESTAMPS,
 };
diff --git a/libavformat/rcwtenc.c b/libavformat/rcwtenc.c
index ed72de81ef..4ccd7b93c8 100644
--- a/libavformat/rcwtenc.c
+++ b/libavformat/rcwtenc.c
@@ -84,10 +84,8 @@ static void rcwt_flush_cluster(AVFormatContext *avf)
 
 static int rcwt_write_header(AVFormatContext *avf)
 {
-    if (avf->nb_streams != 1 || avf->streams[0]->codecpar->codec_id != AV_CODEC_ID_EIA_608) {
-        av_log(avf, AV_LOG_ERROR,
-                "RCWT supports only one CC (608/708) stream, more than one stream was "
-                "provided or its codec type was not CC (608/708)\n");
+    if (avf->streams[0]->codecpar->codec_id != AV_CODEC_ID_EIA_608) {
+        av_log(avf, AV_LOG_ERROR, "RCWT supports only CC (608/708)\n");
         return AVERROR(EINVAL);
     }
 
@@ -168,7 +166,10 @@ const FFOutputFormat ff_rcwt_muxer = {
     .p.long_name        = NULL_IF_CONFIG_SMALL("RCWT (Raw Captions With Time)"),
     .p.extensions       = "bin",
     .p.flags            = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT,
+    .p.video_codec      = AV_CODEC_ID_NONE,
+    .p.audio_codec      = AV_CODEC_ID_NONE,
     .p.subtitle_codec   = AV_CODEC_ID_EIA_608,
+    .flags_internal     = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .priv_data_size     = sizeof(RCWTContext),
     .write_header       = rcwt_write_header,
     .write_packet       = rcwt_write_packet,
diff --git a/libavformat/sccenc.c b/libavformat/sccenc.c
index ea7865ecf2..040d1ac96c 100644
--- a/libavformat/sccenc.c
+++ b/libavformat/sccenc.c
@@ -35,12 +35,6 @@ static int scc_write_header(AVFormatContext *avf)
 {
     SCCContext *scc = avf->priv_data;
 
-    if (avf->nb_streams != 1 ||
-        avf->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
-        av_log(avf, AV_LOG_ERROR,
-               "SCC supports only a single subtitles stream.\n");
-        return AVERROR(EINVAL);
-    }
     if (avf->streams[0]->codecpar->codec_id != AV_CODEC_ID_EIA_608) {
         av_log(avf, AV_LOG_ERROR,
                "Unsupported subtitles codec: %s\n",
@@ -117,7 +111,10 @@ const FFOutputFormat ff_scc_muxer = {
     .p.long_name      = NULL_IF_CONFIG_SMALL("Scenarist Closed Captions"),
     .p.extensions     = "scc",
     .p.flags          = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT,
+    .p.video_codec    = AV_CODEC_ID_NONE,
+    .p.audio_codec    = AV_CODEC_ID_NONE,
     .p.subtitle_codec = AV_CODEC_ID_EIA_608,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .priv_data_size = sizeof(SCCContext),
     .write_header   = scc_write_header,
     .write_packet   = scc_write_packet,
diff --git a/libavformat/segafilmenc.c b/libavformat/segafilmenc.c
index ba06dc655d..88a5b9f972 100644
--- a/libavformat/segafilmenc.c
+++ b/libavformat/segafilmenc.c
@@ -124,10 +124,6 @@ static int film_init(AVFormatContext *format_context)
     for (int i = 0; i < format_context->nb_streams; i++) {
         AVStream *st = format_context->streams[i];
         if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
-            if (film->audio_index > -1) {
-                av_log(format_context, AV_LOG_ERROR, "Sega FILM allows a maximum of one audio stream.\n");
-                return AVERROR(EINVAL);
-            }
             if (get_audio_codec_id(st->codecpar->codec_id) < 0) {
                 av_log(format_context, AV_LOG_ERROR,
                        "Incompatible audio stream format.\n");
@@ -137,10 +133,6 @@ static int film_init(AVFormatContext *format_context)
         }
 
         if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
-            if (film->video_index > -1) {
-                av_log(format_context, AV_LOG_ERROR, "Sega FILM allows a maximum of one video stream.\n");
-                return AVERROR(EINVAL);
-            }
             if (st->codecpar->codec_id != AV_CODEC_ID_CINEPAK &&
                 st->codecpar->codec_id != AV_CODEC_ID_RAWVIDEO) {
                 av_log(format_context, AV_LOG_ERROR,
@@ -287,6 +279,8 @@ const FFOutputFormat ff_segafilm_muxer = {
     .priv_data_size = sizeof(FILMOutputContext),
     .p.audio_codec  = AV_CODEC_ID_PCM_S16BE_PLANAR,
     .p.video_codec  = AV_CODEC_ID_CINEPAK,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .init           = film_init,
     .write_trailer  = film_write_header,
     .write_packet   = film_write_packet,
diff --git a/libavformat/srtenc.c b/libavformat/srtenc.c
index 30dc59e0f8..a8a16a7f50 100644
--- a/libavformat/srtenc.c
+++ b/libavformat/srtenc.c
@@ -39,12 +39,6 @@ static int srt_write_header(AVFormatContext *avf)
 {
     SRTContext *srt = avf->priv_data;
 
-    if (avf->nb_streams != 1 ||
-        avf->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
-        av_log(avf, AV_LOG_ERROR,
-               "SRT supports only a single subtitles stream.\n");
-        return AVERROR(EINVAL);
-    }
     if (avf->streams[0]->codecpar->codec_id != AV_CODEC_ID_TEXT &&
         avf->streams[0]->codecpar->codec_id != AV_CODEC_ID_SUBRIP) {
         av_log(avf, AV_LOG_ERROR,
@@ -103,7 +97,10 @@ const FFOutputFormat ff_srt_muxer = {
     .p.mime_type      = "application/x-subrip",
     .p.extensions     = "srt",
     .p.flags          = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT,
+    .p.video_codec    = AV_CODEC_ID_NONE,
+    .p.audio_codec    = AV_CODEC_ID_NONE,
     .p.subtitle_codec = AV_CODEC_ID_SUBRIP,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .priv_data_size = sizeof(SRTContext),
     .write_header   = srt_write_header,
     .write_packet   = srt_write_packet,
diff --git a/libavformat/supenc.c b/libavformat/supenc.c
index 4af92fefa2..9d5ca51894 100644
--- a/libavformat/supenc.c
+++ b/libavformat/supenc.c
@@ -74,12 +74,6 @@ static int sup_write_packet(AVFormatContext *s, AVPacket *pkt)
 
 static int sup_write_header(AVFormatContext *s)
 {
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "%s files have exactly one stream\n",
-               s->oformat->name);
-        return AVERROR(EINVAL);
-    }
-
     avpriv_set_pts_info(s->streams[0], 32, 1, 90000);
 
     return 0;
@@ -90,8 +84,11 @@ const FFOutputFormat ff_sup_muxer = {
     .p.long_name      = NULL_IF_CONFIG_SMALL("raw HDMV Presentation Graphic Stream subtitles"),
     .p.extensions     = "sup",
     .p.mime_type      = "application/x-pgs",
+    .p.video_codec    = AV_CODEC_ID_NONE,
+    .p.audio_codec    = AV_CODEC_ID_NONE,
     .p.subtitle_codec = AV_CODEC_ID_HDMV_PGS_SUBTITLE,
     .p.flags          = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT,
+    .flags_internal   = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_header   = sup_write_header,
     .write_packet   = sup_write_packet,
 };
diff --git a/libavformat/swfenc.c b/libavformat/swfenc.c
index f9ac69539b..d106e16d19 100644
--- a/libavformat/swfenc.c
+++ b/libavformat/swfenc.c
@@ -208,10 +208,6 @@ static int swf_write_header(AVFormatContext *s)
     for(i=0;i<s->nb_streams;i++) {
         AVCodecParameters *par = s->streams[i]->codecpar;
         if (par->codec_type == AVMEDIA_TYPE_AUDIO) {
-            if (swf->audio_par) {
-                av_log(s, AV_LOG_ERROR, "SWF muxer only supports 1 audio stream\n");
-                return AVERROR_INVALIDDATA;
-            }
             if (par->codec_id == AV_CODEC_ID_MP3) {
                 swf->audio_par = par;
                 swf->audio_fifo = av_fifo_alloc2(AUDIO_FIFO_SIZE, 1, 0);
@@ -222,10 +218,6 @@ static int swf_write_header(AVFormatContext *s)
                 return -1;
             }
         } else {
-            if (swf->video_par) {
-                av_log(s, AV_LOG_ERROR, "SWF muxer only supports 1 video stream\n");
-                return AVERROR_INVALIDDATA;
-            }
             if (ff_codec_get_tag(ff_swf_codec_tags, par->codec_id) ||
                 par->codec_id == AV_CODEC_ID_PNG ||
                 par->codec_id == AV_CODEC_ID_MJPEG) {
@@ -556,11 +548,13 @@ const FFOutputFormat ff_swf_muxer = {
     .priv_data_size    = sizeof(SWFEncContext),
     .p.audio_codec     = AV_CODEC_ID_MP3,
     .p.video_codec     = AV_CODEC_ID_FLV1,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
     .write_header      = swf_write_header,
     .write_packet      = swf_write_packet,
     .write_trailer     = swf_write_trailer,
     .deinit            = swf_deinit,
     .p.flags           = AVFMT_TS_NONSTRICT,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
 };
 #endif
 #if CONFIG_AVM2_MUXER
@@ -571,10 +565,12 @@ const FFOutputFormat ff_avm2_muxer = {
     .priv_data_size    = sizeof(SWFEncContext),
     .p.audio_codec     = AV_CODEC_ID_MP3,
     .p.video_codec     = AV_CODEC_ID_FLV1,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
     .write_header      = swf_write_header,
     .write_packet      = swf_write_packet,
     .write_trailer     = swf_write_trailer,
     .deinit            = swf_deinit,
     .p.flags           = AVFMT_TS_NONSTRICT,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
 };
 #endif
diff --git a/libavformat/ttaenc.c b/libavformat/ttaenc.c
index c7f7e065dc..661aa8fc83 100644
--- a/libavformat/ttaenc.c
+++ b/libavformat/ttaenc.c
@@ -40,13 +40,7 @@ typedef struct TTAMuxContext {
 static int tta_init(AVFormatContext *s)
 {
     TTAMuxContext *tta = s->priv_data;
-    AVCodecParameters *par;
-
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "Only one stream is supported\n");
-        return AVERROR(EINVAL);
-    }
-    par = s->streams[0]->codecpar;
+    AVCodecParameters *par = s->streams[0]->codecpar;
 
     if (par->codec_id != AV_CODEC_ID_TTA) {
         av_log(s, AV_LOG_ERROR, "Unsupported codec\n");
@@ -174,6 +168,8 @@ const FFOutputFormat ff_tta_muxer = {
     .priv_data_size    = sizeof(TTAMuxContext),
     .p.audio_codec     = AV_CODEC_ID_TTA,
     .p.video_codec     = AV_CODEC_ID_NONE,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .init              = tta_init,
     .deinit            = tta_deinit,
     .write_header      = tta_write_header,
diff --git a/libavformat/ttmlenc.c b/libavformat/ttmlenc.c
index 212994be50..0af82d5753 100644
--- a/libavformat/ttmlenc.c
+++ b/libavformat/ttmlenc.c
@@ -126,8 +126,7 @@ static int ttml_write_header(AVFormatContext *ctx)
     TTMLMuxContext *ttml_ctx = ctx->priv_data;
     ttml_ctx->document_written = 0;
 
-    if (ctx->nb_streams != 1 ||
-        ctx->streams[0]->codecpar->codec_id != AV_CODEC_ID_TTML) {
+    if (ctx->streams[0]->codecpar->codec_id != AV_CODEC_ID_TTML) {
         av_log(ctx, AV_LOG_ERROR, "Exactly one TTML stream is required!\n");
         return AVERROR(EINVAL);
     }
@@ -224,7 +223,10 @@ const FFOutputFormat ff_ttml_muxer = {
     .priv_data_size    = sizeof(TTMLMuxContext),
     .p.flags           = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS |
                          AVFMT_TS_NONSTRICT,
+    .p.video_codec     = AV_CODEC_ID_NONE,
+    .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.subtitle_codec  = AV_CODEC_ID_TTML,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
     .write_header      = ttml_write_header,
     .write_packet      = ttml_write_packet,
     .write_trailer     = ttml_write_trailer,
diff --git a/libavformat/wavenc.c b/libavformat/wavenc.c
index 19daa813a0..7e853ce2fb 100644
--- a/libavformat/wavenc.c
+++ b/libavformat/wavenc.c
@@ -304,11 +304,6 @@ static int wav_write_header(AVFormatContext *s)
     AVIOContext *pb = s->pb;
     int64_t fmt;
 
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "WAVE files have exactly one stream\n");
-        return AVERROR(EINVAL);
-    }
-
     if (wav->rf64 == RF64_ALWAYS) {
         ffio_wfourcc(pb, "RF64");
         avio_wl32(pb, -1); /* RF64 chunk size: use size in ds64 */
@@ -516,6 +511,7 @@ const FFOutputFormat ff_wav_muxer = {
     .priv_data_size    = sizeof(WAVMuxContext),
     .p.audio_codec     = AV_CODEC_ID_PCM_S16LE,
     .p.video_codec     = AV_CODEC_ID_NONE,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
     .write_header      = wav_write_header,
     .write_packet      = wav_write_packet,
     .write_trailer     = wav_write_trailer,
@@ -523,22 +519,13 @@ const FFOutputFormat ff_wav_muxer = {
     .p.flags           = AVFMT_TS_NONSTRICT,
     .p.codec_tag       = ff_wav_codec_tags_list,
     .p.priv_class      = &wav_muxer_class,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
 };
 #endif /* CONFIG_WAV_MUXER */
 
 #if CONFIG_W64_MUXER
 #include "w64.h"
 
-static av_cold int w64_init(AVFormatContext *ctx)
-{
-    if (ctx->nb_streams != 1) {
-        av_log(ctx, AV_LOG_ERROR, "This muxer only supports a single stream.\n");
-        return AVERROR(EINVAL);
-    }
-
-    return 0;
-}
-
 static void start_guid(AVIOContext *pb, const uint8_t *guid, int64_t *pos)
 {
     *pos = avio_tell(pb);
@@ -624,11 +611,12 @@ const FFOutputFormat ff_w64_muxer = {
     .priv_data_size    = sizeof(WAVMuxContext),
     .p.audio_codec     = AV_CODEC_ID_PCM_S16LE,
     .p.video_codec     = AV_CODEC_ID_NONE,
-    .init              = w64_init,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
     .write_header      = w64_write_header,
     .write_packet      = wav_write_packet,
     .write_trailer     = w64_write_trailer,
     .p.flags           = AVFMT_TS_NONSTRICT,
     .p.codec_tag       = ff_wav_codec_tags_list,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
 };
 #endif /* CONFIG_W64_MUXER */
diff --git a/libavformat/webpenc.c b/libavformat/webpenc.c
index ea7a321975..85074ae315 100644
--- a/libavformat/webpenc.c
+++ b/libavformat/webpenc.c
@@ -42,10 +42,6 @@ static int webp_init(AVFormatContext *s)
 
     w->last_pkt = ffformatcontext(s)->pkt;
 
-    if (s->nb_streams != 1) {
-        av_log(s, AV_LOG_ERROR, "Only exactly 1 stream is supported\n");
-        return AVERROR(EINVAL);
-    }
     st = s->streams[0];
     if (st->codecpar->codec_id != AV_CODEC_ID_WEBP) {
         av_log(s, AV_LOG_ERROR, "Only WebP is supported\n");
@@ -230,9 +226,12 @@ const FFOutputFormat ff_webp_muxer = {
     .p.extensions   = "webp",
     .priv_data_size = sizeof(WebpContext),
     .p.video_codec  = AV_CODEC_ID_WEBP,
+    .p.audio_codec    = AV_CODEC_ID_NONE,
+    .p.subtitle_codec = AV_CODEC_ID_NONE,
     .init           = webp_init,
     .write_packet   = webp_write_packet,
     .write_trailer  = webp_write_trailer,
     .p.priv_class   = &webp_muxer_class,
     .p.flags        = AVFMT_VARIABLE_FPS,
+    .flags_internal = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
 };
diff --git a/libavformat/webvttenc.c b/libavformat/webvttenc.c
index 1337045325..12a4b776dc 100644
--- a/libavformat/webvttenc.c
+++ b/libavformat/webvttenc.c
@@ -50,7 +50,7 @@ static int webvtt_write_header(AVFormatContext *ctx)
     AVCodecParameters *par = ctx->streams[0]->codecpar;
     AVIOContext *pb = ctx->pb;
 
-    if (ctx->nb_streams != 1 || par->codec_id != AV_CODEC_ID_WEBVTT) {
+    if (par->codec_id != AV_CODEC_ID_WEBVTT) {
         av_log(ctx, AV_LOG_ERROR, "Exactly one WebVTT stream is needed.\n");
         return AVERROR(EINVAL);
     }
@@ -109,7 +109,10 @@ const FFOutputFormat ff_webvtt_muxer = {
     .p.extensions      = "vtt",
     .p.mime_type       = "text/vtt",
     .p.flags           = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT,
+    .p.video_codec     = AV_CODEC_ID_NONE,
+    .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.subtitle_codec  = AV_CODEC_ID_WEBVTT,
     .write_header      = webvtt_write_header,
     .write_packet      = webvtt_write_packet,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
 };
diff --git a/libavformat/westwood_audenc.c b/libavformat/westwood_audenc.c
index 46456e2ecb..2240d130b6 100644
--- a/libavformat/westwood_audenc.c
+++ b/libavformat/westwood_audenc.c
@@ -59,11 +59,6 @@ static int wsaud_write_init(AVFormatContext *ctx)
         return AVERROR(EINVAL);
     }
 
-    if (ctx->nb_streams != 1) {
-        av_log(ctx, AV_LOG_ERROR, "AUD files have exactly one stream\n");
-        return AVERROR(EINVAL);
-    }
-
     return 0;
 }
 
@@ -133,8 +128,10 @@ const FFOutputFormat ff_wsaud_muxer = {
     .priv_data_size    = sizeof(AUDMuxContext),
     .p.audio_codec     = AV_CODEC_ID_ADPCM_IMA_WS,
     .p.video_codec     = AV_CODEC_ID_NONE,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
     .init              = wsaud_write_init,
     .write_header      = wsaud_write_header,
     .write_packet      = wsaud_write_packet,
     .write_trailer     = wsaud_write_trailer,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
 };
diff --git a/libavformat/wvenc.c b/libavformat/wvenc.c
index 9d9190f252..6d5fefe1bc 100644
--- a/libavformat/wvenc.c
+++ b/libavformat/wvenc.c
@@ -33,8 +33,7 @@ typedef struct WvMuxContext {
 
 static av_cold int wv_init(AVFormatContext *ctx)
 {
-    if (ctx->nb_streams > 1 ||
-        ctx->streams[0]->codecpar->codec_id != AV_CODEC_ID_WAVPACK) {
+    if (ctx->streams[0]->codecpar->codec_id != AV_CODEC_ID_WAVPACK) {
         av_log(ctx, AV_LOG_ERROR, "This muxer only supports a single WavPack stream.\n");
         return AVERROR(EINVAL);
     }
@@ -85,8 +84,10 @@ const FFOutputFormat ff_wv_muxer = {
     .priv_data_size    = sizeof(WvMuxContext),
     .p.audio_codec     = AV_CODEC_ID_WAVPACK,
     .p.video_codec     = AV_CODEC_ID_NONE,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
     .init              = wv_init,
     .write_packet      = wv_write_packet,
     .write_trailer     = wv_write_trailer,
     .p.flags           = AVFMT_NOTIMESTAMPS,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
 };
diff --git a/libavformat/yuv4mpegenc.c b/libavformat/yuv4mpegenc.c
index 1d641eb9e4..35397cbde0 100644
--- a/libavformat/yuv4mpegenc.c
+++ b/libavformat/yuv4mpegenc.c
@@ -221,9 +221,6 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
 
 static int yuv4_init(AVFormatContext *s)
 {
-    if (s->nb_streams != 1)
-        return AVERROR(EIO);
-
     if (s->streams[0]->codecpar->codec_id != AV_CODEC_ID_WRAPPED_AVFRAME &&
         s->streams[0]->codecpar->codec_id != AV_CODEC_ID_RAWVIDEO) {
         av_log(s, AV_LOG_ERROR, "ERROR: Codec not supported.\n");
@@ -297,7 +294,9 @@ const FFOutputFormat ff_yuv4mpegpipe_muxer = {
     .p.extensions      = "y4m",
     .p.audio_codec     = AV_CODEC_ID_NONE,
     .p.video_codec     = AV_CODEC_ID_WRAPPED_AVFRAME,
+    .p.subtitle_codec  = AV_CODEC_ID_NONE,
     .init              = yuv4_init,
     .write_header      = yuv4_write_header,
     .write_packet      = yuv4_write_packet,
+    .flags_internal    = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
 };
