diff options
author | Andrey Semashev <andrey.semashev@gmail.com> | 2018-11-17 20:40:50 +0300 |
---|---|---|
committer | Karthick J <kjeyapal@akamai.com> | 2018-11-21 18:01:53 +0530 |
commit | 322e53f8aebb50cab0c3138c04b950f95fc455e5 (patch) | |
tree | 14ca54dc9c725fb277cfe13051f265c4fb2bc6a6 /libavformat | |
parent | 1ee4b4006be6c34a0dfec367a60942b85d13238e (diff) | |
download | ffmpeg-322e53f8aebb50cab0c3138c04b950f95fc455e5.tar.gz |
lavf/dashenc: Add DASH segment type auto and make it the default
This commit restores the ability to create DASH streams with codecs
that require different containers that was lost after commit
2efdbf7367989cf9d296c25fa3d2aff8d6e25fdd. It adds a new "auto" value for
the dash_segment_type option and makes it the default. When in this mode,
the segment format will be chosen based on the codec used in the stream:
webm for Vorbis, Opus, VP8 or VP9, mp4 otherwise.
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/dashenc.c | 72 |
1 files changed, 54 insertions, 18 deletions
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index d151921175..0af7b85c5f 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -49,7 +49,8 @@ #include "dash.h" typedef enum { - SEGMENT_TYPE_MP4 = 0, + SEGMENT_TYPE_AUTO = 0, + SEGMENT_TYPE_MP4, SEGMENT_TYPE_WEBM, SEGMENT_TYPE_NB } SegmentType; @@ -84,6 +85,8 @@ typedef struct OutputStream { int64_t first_pts, start_pts, max_pts; int64_t last_dts, last_pts; int bit_rate; + SegmentType segment_type; /* segment type selected for this particular stream */ + const char *format_name; char codec_str[100]; int written_len; @@ -131,8 +134,7 @@ typedef struct DASHContext { int64_t timeout; int index_correction; char *format_options_str; - SegmentType segment_type; - const char *format_name; + SegmentType segment_type_option; /* segment type as specified in options */ } DASHContext; static struct codec_string { @@ -151,6 +153,7 @@ static struct format_string { SegmentType segment_type; const char *str; } formats[] = { + { SEGMENT_TYPE_AUTO, "auto" }, { SEGMENT_TYPE_MP4, "mp4" }, { SEGMENT_TYPE_WEBM, "webm" }, { 0, NULL } @@ -197,6 +200,38 @@ static const char *get_format_str(SegmentType segment_type) { return NULL; } +static inline SegmentType select_segment_type(SegmentType segment_type, AVCodecID codec_id) +{ + if (segment_type == SEGMENT_TYPE_AUTO) { + if (codec_id == AV_CODEC_ID_OPUS || codec_id == AV_CODEC_ID_VORBIS || + codec_id == AV_CODEC_ID_VP8 || codec_id == AV_CODEC_ID_VP9) { + segment_type = SEGMENT_TYPE_WEBM; + } else { + segment_type = SEGMENT_TYPE_MP4; + } + } + + return segment_type; +} + +static int init_segment_types(AVFormatContext *s) +{ + DASHContext *c = s->priv_data; + for (int i = 0; i < s->nb_streams; ++i) { + OutputStream *os = &c->streams[i]; + SegmentType segment_type = select_segment_type( + c->segment_type_option, s->streams[i]->codecpar->codec_id); + os->segment_type = segment_type; + os->format_name = get_format_str(segment_type); + if (!os->format_name) { + av_log(s, AV_LOG_ERROR, "Could not select DASH segment type for stream %d\n", i); + return AVERROR_MUXER_NOT_FOUND; + } + } + + return 0; +} + static int check_file_extension(const char *filename, const char *extension) { char *dot; if (!filename || !extension) @@ -622,13 +657,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\t<Representation id=\"%d\" mimeType=\"video/%s\" codecs=\"%s\"%s width=\"%d\" height=\"%d\"", - i, c->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height); + i, os->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<Representation id=\"%d\" mimeType=\"audio/%s\" codecs=\"%s\"%s audioSamplingRate=\"%d\">\n", - i, c->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->sample_rate); + i, os->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->sample_rate); avio_printf(out, "\t\t\t\t<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\" />\n", s->streams[i]->codecpar->channels); } @@ -993,6 +1028,9 @@ static int dash_init(AVFormatContext *s) if ((ret = parse_adaptation_sets(s)) < 0) return ret; + if ((ret = init_segment_types(s)) < 0) + return ret; + for (i = 0; i < s->nb_streams; i++) { OutputStream *os = &c->streams[i]; AdaptationSet *as = &c->as[os->as_idx - 1]; @@ -1018,13 +1056,10 @@ static int dash_init(AVFormatContext *s) if (!ctx) return AVERROR(ENOMEM); - c->format_name = get_format_str(c->segment_type); - if (!c->format_name) - return AVERROR_MUXER_NOT_FOUND; - if (c->segment_type == SEGMENT_TYPE_WEBM) { - if ((!c->single_file && check_file_extension(c->init_seg_name, c->format_name) != 0) || - (!c->single_file && check_file_extension(c->media_seg_name, c->format_name) != 0) || - (c->single_file && check_file_extension(c->single_file_name, c->format_name) != 0)) { + if (os->segment_type == SEGMENT_TYPE_WEBM) { + if ((!c->single_file && check_file_extension(c->init_seg_name, os->format_name) != 0) || + (!c->single_file && check_file_extension(c->media_seg_name, os->format_name) != 0) || + (c->single_file && check_file_extension(c->single_file_name, os->format_name) != 0)) { av_log(s, AV_LOG_WARNING, "One or many segment file names doesn't end with .webm. " "Override -init_seg_name and/or -media_seg_name and/or " @@ -1032,7 +1067,7 @@ static int dash_init(AVFormatContext *s) } } - ctx->oformat = av_guess_format(c->format_name, NULL, NULL); + ctx->oformat = av_guess_format(os->format_name, NULL, NULL); if (!ctx->oformat) return AVERROR_MUXER_NOT_FOUND; os->ctx = ctx; @@ -1076,7 +1111,7 @@ static int dash_init(AVFormatContext *s) return ret; } - if (c->segment_type == SEGMENT_TYPE_MP4) { + if (os->segment_type == SEGMENT_TYPE_MP4) { if (c->streaming) av_dict_set(&opts, "movflags", "frag_every_frame+dash+delay_moov+global_sidx", 0); else @@ -1141,7 +1176,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 (c->segment_type == SEGMENT_TYPE_WEBM && + if (os->segment_type == SEGMENT_TYPE_WEBM && (ret = flush_init_segment(s, os)) < 0) return ret; } @@ -1312,7 +1347,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream) } if (!c->single_file) { - if (c->segment_type == SEGMENT_TYPE_MP4 && !os->written_len) + if (os->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); @@ -1502,7 +1537,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) } //write out the data immediately in streaming mode - if (c->streaming && c->segment_type == SEGMENT_TYPE_MP4) { + if (c->streaming && os->segment_type == SEGMENT_TYPE_MP4) { int len = 0; uint8_t *buf = NULL; if (!os->written_len) @@ -1598,7 +1633,8 @@ 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"}, + { "dash_segment_type", "set dash segment files type", OFFSET(segment_type_option), AV_OPT_TYPE_INT, {.i64 = SEGMENT_TYPE_AUTO }, 0, SEGMENT_TYPE_NB - 1, E, "segment_type"}, + { "auto", "select segment file format based on codec", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_AUTO }, 0, UINT_MAX, 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 }, |