diff --git a/doc/muxers.texi b/doc/muxers.texi index 59e20bf426..80c65420ba 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -288,6 +288,15 @@ the segment indexes fall behind the expected real time position. Set container format (mp4/webm) options using a @code{:} separated list of key=value parameters. Values containing @code{:} special characters must be escaped. + +@item dash_segment_type @var{dash_segment_type} +Possible values: +@item mp4 +If this flag is set, the dash segment files will be in in ISOBMFF format. This is the default format. + +@item webm +If this flag is set, the dash segment files will be in in WebM format. + @end table @anchor{framecrc} diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index e27b61c096..56af916555 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -48,6 +48,12 @@ #include "vpcc.h" #include "dash.h" +typedef enum { + SEGMENT_TYPE_MP4 = 0, + SEGMENT_TYPE_WEBM, + SEGMENT_TYPE_NB +} SegmentType; + typedef struct Segment { char file[1024]; int64_t start_pos; @@ -69,7 +75,6 @@ typedef struct OutputStream { AVFormatContext *ctx; int ctx_inited, as_idx; AVIOContext *out; - char format_name[8]; int packets_written; char initfile[1024]; int64_t init_start_pos, pos; @@ -126,6 +131,8 @@ typedef struct DASHContext { int64_t timeout; int index_correction; char *format_options_str; + SegmentType segment_type; + const char *format_name; } DASHContext; static struct codec_string { @@ -139,6 +146,15 @@ static struct codec_string { { 0, NULL } }; +static struct format_string { + SegmentType segment_type; + const char *str; +} formats[] = { + { SEGMENT_TYPE_MP4, "mp4" }, + { SEGMENT_TYPE_WEBM, "webm" }, + { 0, NULL } +}; + static int dashenc_io_open(AVFormatContext *s, AVIOContext **pb, char *filename, AVDictionary **options) { DASHContext *c = s->priv_data; @@ -172,6 +188,14 @@ static void dashenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filenam } } +static const char *get_format_str(SegmentType segment_type) { + int i; + for (i = 0; i < SEGMENT_TYPE_NB; i++) + if (formats[i].segment_type == segment_type) + return formats[i].str; + return NULL; +} + static void set_vp9_codec_str(AVFormatContext *s, AVCodecParameters *par, AVRational *frame_rate, char *str, int size) { VPCC vpcc; @@ -582,13 +606,13 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind if (as->media_type == AVMEDIA_TYPE_VIDEO) { AVStream *st = s->streams[i]; avio_printf(out, "\t\t\tformat_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height); + i, c->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height); if (st->avg_frame_rate.num) avio_printf(out, " frameRate=\"%d/%d\"", st->avg_frame_rate.num, st->avg_frame_rate.den); avio_printf(out, ">\n"); } else { avio_printf(out, "\t\t\t\n", - i, os->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->sample_rate); + i, c->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->sample_rate); avio_printf(out, "\t\t\t\t\n", s->streams[i]->codecpar->channels); } @@ -960,27 +984,10 @@ static int dash_init(AVFormatContext *s) if (!ctx) return AVERROR(ENOMEM); - // choose muxer based on codec: webm for VP8 and opus, mp4 otherwise - // note: os->format_name is also used as part of the mimetype of the - // representation, e.g. video/ - if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_VP8 || - s->streams[i]->codecpar->codec_id == AV_CODEC_ID_OPUS || - s->streams[i]->codecpar->codec_id == AV_CODEC_ID_VORBIS) { - snprintf(os->format_name, sizeof(os->format_name), "webm"); - - if (s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { - av_log(s, AV_LOG_ERROR, - "WebM support in dashenc is experimental and has not " - "been validated. For testing purposes, make sure " - "to add -strict experimental and override " - "-init_seg_name and -media_seg_name to end with " - "the extension 'webm'.\n"); - return AVERROR(EINVAL); - } - } else { - snprintf(os->format_name, sizeof(os->format_name), "mp4"); - } - ctx->oformat = av_guess_format(os->format_name, NULL, NULL); + c->format_name = get_format_str(c->segment_type); + if (!c->format_name) + return AVERROR_MUXER_NOT_FOUND; + ctx->oformat = av_guess_format(c->format_name, NULL, NULL); if (!ctx->oformat) return AVERROR_MUXER_NOT_FOUND; os->ctx = ctx; @@ -1023,7 +1030,8 @@ static int dash_init(AVFormatContext *s) if (ret < 0) return ret; } - if (!strcmp(os->format_name, "mp4")) { + + if (c->segment_type == SEGMENT_TYPE_MP4) { if (c->streaming) av_dict_set(&opts, "movflags", "frag_every_frame+dash+delay_moov", 0); else @@ -1088,7 +1096,7 @@ static int dash_write_header(AVFormatContext *s) // Flush init segment // Only for WebM segment, since for mp4 delay_moov is set and // the init segment is thus flushed after the first packets. - if (strcmp(os->format_name, "mp4") && + if (c->segment_type == SEGMENT_TYPE_WEBM && (ret = flush_init_segment(s, os)) < 0) return ret; } @@ -1259,7 +1267,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream) } if (!c->single_file) { - if (!strcmp(os->format_name, "mp4") && !os->written_len) + if (c->segment_type == SEGMENT_TYPE_MP4 && !os->written_len) write_styp(os->ctx->pb); } else { snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname, os->initfile); @@ -1449,7 +1457,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) } //write out the data immediately in streaming mode - if (c->streaming && !strcmp(os->format_name, "mp4")) { + if (c->streaming && c->segment_type == SEGMENT_TYPE_MP4) { int len = 0; uint8_t *buf = NULL; if (!os->written_len) @@ -1545,6 +1553,9 @@ static const AVOption options[] = { { "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E }, { "index_correction", "Enable/Disable segment index correction logic", OFFSET(index_correction), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, { "format_options","set list of options for the container format (mp4/webm) used for dash", OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + { "dash_segment_type", "set dash segment files type", OFFSET(segment_type), AV_OPT_TYPE_INT, {.i64 = SEGMENT_TYPE_MP4 }, 0, SEGMENT_TYPE_NB - 1, E, "segment_type"}, + { "mp4", "make segment file in ISOBMFF format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_MP4 }, 0, UINT_MAX, E, "segment_type"}, + { "webm", "make segment file in WebM format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_WEBM }, 0, UINT_MAX, E, "segment_type"}, { NULL }, };