summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Semashev <andrey.semashev@gmail.com>2018-11-17 20:40:50 +0300
committerKarthick J <kjeyapal@akamai.com>2018-11-21 18:01:53 +0530
commit322e53f8aebb50cab0c3138c04b950f95fc455e5 (patch)
tree14ca54dc9c725fb277cfe13051f265c4fb2bc6a6
parent1ee4b4006be6c34a0dfec367a60942b85d13238e (diff)
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.
-rw-r--r--doc/muxers.texi7
-rw-r--r--libavformat/dashenc.c72
2 files changed, 59 insertions, 20 deletions
diff --git a/doc/muxers.texi b/doc/muxers.texi
index 62f4091e31..2fed5cf3d4 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -289,10 +289,13 @@ 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}
+@item -dash_segment_type @var{dash_segment_type}
Possible values:
+@item auto
+If this flag is set, the dash segment files format will be selected based on the stream codec. This is the default mode.
+
@item mp4
-If this flag is set, the dash segment files will be in in ISOBMFF format. This is the default format.
+If this flag is set, the dash segment files will be in in ISOBMFF format.
@item webm
If this flag is set, the dash segment files will be in in WebM format.
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 },