[FFmpeg-devel] [PATCH 1/4] lavf/dashenc: Add DASH segment type auto and make it the default
Andrey Semashev
andrey.semashev at gmail.com
Sat Nov 17 19:40:50 EET 2018
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.
---
doc/muxers.texi | 7 +++--
libavformat/dashenc.c | 72 ++++++++++++++++++++++++++++++++-----------
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.
- at item dash_segment_type @var{dash_segment_type}
+ at item -dash_segment_type @var{dash_segment_type}
Possible values:
+ at 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 },
--
2.19.1
More information about the ffmpeg-devel
mailing list