On Fri, 27 Jan 2017, Peter Große wrote:
Use webm muxer for VP8, VP9 and Opus codec, mp4 muxer otherwise.
Also copy stream metadata to output stream.
Signed-off-by: Peter Große <[email protected]>
---
libavformat/dashenc.c | 68 ++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 54 insertions(+), 14 deletions(-)
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 86b454e..24665cd 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -113,6 +113,23 @@ static void set_codec_str(AVFormatContext *s,
AVCodecParameters *par,
{
const AVCodecTag *tags[2] = { NULL, NULL };
uint32_t tag;
+
+ // common Webm codecs are not part of RFC 6381
+ switch (par->codec_id) {
+ case AV_CODEC_ID_VP8:
+ snprintf(str, size, "vp8");
+ return;
+ case AV_CODEC_ID_VP9:
+ snprintf(str, size, "vp9");
+ return;
+ case AV_CODEC_ID_VORBIS:
+ snprintf(str, size, "vorbis");
+ return;
+ case AV_CODEC_ID_OPUS:
+ snprintf(str, size, "opus");
+ return;
+ }
+
Hmm, I'm pondering if it'd be worth to store these in some more compact
form, like a table, for all codecs which just have a single simple plain
string?
if (par->codec_type == AVMEDIA_TYPE_VIDEO)
tags[0] = ff_codec_movvideo_tags;
else if (par->codec_type == AVMEDIA_TYPE_AUDIO)
@@ -495,11 +512,11 @@ static int write_adaptation_set(AVFormatContext *s,
AVIOContext *out, int as_ind
continue;
if (as->media_type == AVMEDIA_TYPE_VIDEO) {
- avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"video/mp4\" codecs=\"%s\"%s
width=\"%d\" height=\"%d\">\n",
- i, os->codec_str, os->bandwidth_str, s->streams[i]->codecpar->width,
s->streams[i]->codecpar->height);
+ avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"video/%s\" codecs=\"%s\"%s
width=\"%d\" height=\"%d\">\n",
+ i, os->ctx->oformat->name, os->codec_str, os->bandwidth_str,
s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
} else {
- avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"audio/mp4\"
codecs=\"%s\"%s audioSamplingRate=\"%d\">\n",
- i, os->codec_str, os->bandwidth_str,
s->streams[i]->codecpar->sample_rate);
+ avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"audio/%s\"
codecs=\"%s\"%s audioSamplingRate=\"%d\">\n",
+ i, os->ctx->oformat->name, os->codec_str, os->bandwidth_str,
s->streams[i]->codecpar->sample_rate);
Using oformat->name here feels a little fragile. I think I'd rather have
that stored as a string somewhere in the context. (Not sure if it's better
to have it "flexible" to compose it as video/<string> and audio/<string>,
or store the full "video/mp4" etc as audioMime and videoMime.)
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);
}
@@ -700,11 +717,18 @@ static int dict_copy_entry(AVDictionary **dst, const
AVDictionary *src, const ch
return 0;
}
+static int dict_set_int(AVDictionary **pm, const char *key, int64_t value, int
flags)
+{
+ char valuestr[22];
+ snprintf(valuestr, sizeof(valuestr), "%"PRId64, value);
+ flags &= ~AV_DICT_DONT_STRDUP_VAL;
+ return av_dict_set(pm, key, valuestr, flags);
+}
+
static int dash_write_header(AVFormatContext *s)
{
DASHContext *c = s->priv_data;
int ret = 0, i, range_length;
- AVOutputFormat *oformat;
char *ptr;
char basename[1024];
@@ -727,12 +751,6 @@ static int dash_write_header(AVFormatContext *s)
if (ptr)
*ptr = '\0';
- oformat = av_guess_format("mp4", NULL, NULL);
- if (!oformat) {
- ret = AVERROR_MUXER_NOT_FOUND;
- goto fail;
- }
-
c->streams = av_mallocz(sizeof(*c->streams) * s->nb_streams);
if (!c->streams) {
ret = AVERROR(ENOMEM);
@@ -784,12 +802,25 @@ static int dash_write_header(AVFormatContext *s)
ret = AVERROR(ENOMEM);
goto fail;
}
+
+ // choose muxer based on codec: webm for VP8/9 and opus, mp4 otherwise
+ if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_VP8 ||
+ s->streams[i]->codecpar->codec_id == AV_CODEC_ID_VP9 ||
+ s->streams[i]->codecpar->codec_id == AV_CODEC_ID_OPUS) {
+ ctx->oformat = av_guess_format("webm", NULL, NULL);
+ } else {
+ ctx->oformat = av_guess_format("mp4", NULL, NULL);
+ }
+ if (!ctx->oformat) {
+ ret = AVERROR_MUXER_NOT_FOUND;
+ goto fail;
+ }
os->ctx = ctx;
- ctx->oformat = oformat;
ctx->interrupt_callback = s->interrupt_callback;
ctx->opaque = s->opaque;
ctx->io_close = s->io_close;
ctx->io_open = s->io_open;
+ av_dict_copy(&ctx->metadata, s->metadata, 0);
Does the webm muxer need some specific metadata which we don't pass
through right now, or is it just for making sure that metadata ends up set
on the chained muxer and included in the stream? I'd at least want a
comment in the commit message explaining why this is necessary.
if (!(st = avformat_new_stream(ctx, NULL))) {
ret = AVERROR(ENOMEM);
@@ -798,7 +829,10 @@ static int dash_write_header(AVFormatContext *s)
avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar);
st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio;
st->time_base = s->streams[i]->time_base;
+ st->avg_frame_rate = s->streams[i]->avg_frame_rate;
ctx->avoid_negative_ts = s->avoid_negative_ts;
+ ctx->flags = s->flags;
+ ctx->max_delay = s->max_delay;
Are these new settings strictly necessary for chained-webm? If not, I'd
rather add them in a separate commit afterwards, with an explanation on
what it helps for.
// Martin
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel