X-Git-Url: https://git.piment-noir.org/?p=deb_ffmpeg.git;a=blobdiff_plain;f=ffmpeg%2Flibavformat%2Fwebmdashenc.c;fp=ffmpeg%2Flibavformat%2Fwebmdashenc.c;h=4536b7d5a8ecb13e1fcae0211f02edf0c9d1f4dc;hp=77f6170a26ab2e3d60cf34a55e0831646fb2d4aa;hb=f6fa7814ccfe3e76514b36cf04f5cd3cb657c8cf;hpb=2ba45a602cbfa7b771effba9b11bb4245c21bc00 diff --git a/ffmpeg/libavformat/webmdashenc.c b/ffmpeg/libavformat/webmdashenc.c index 77f6170..4536b7d 100644 --- a/ffmpeg/libavformat/webmdashenc.c +++ b/ffmpeg/libavformat/webmdashenc.c @@ -46,6 +46,7 @@ typedef struct WebMDashMuxContext { char *adaptation_sets; AdaptationSet *as; int nb_as; + int representation_id; } WebMDashMuxContext; static const char *get_codec_name(int codec_id) @@ -95,7 +96,7 @@ static void write_header(AVFormatContext *s) static void write_footer(AVFormatContext *s) { - avio_printf(s->pb, ""); + avio_printf(s->pb, "\n"); } static int subsegment_alignment(AVFormatContext *s, AdaptationSet *as) { @@ -132,6 +133,80 @@ static int bitstream_switching(AVFormatContext *s, AdaptationSet *as) { return 1; } +/* + * Writes a Representation within an Adaptation Set. Returns 0 on success and + * < 0 on failure. + */ +static int write_representation(AVFormatContext *s, AVStream *stream, int id, + int output_width, int output_height, + int output_sample_rate) { + AVDictionaryEntry *irange = av_dict_get(stream->metadata, INITIALIZATION_RANGE, NULL, 0); + AVDictionaryEntry *cues_start = av_dict_get(stream->metadata, CUES_START, NULL, 0); + AVDictionaryEntry *cues_end = av_dict_get(stream->metadata, CUES_END, NULL, 0); + AVDictionaryEntry *filename = av_dict_get(stream->metadata, FILENAME, NULL, 0); + AVDictionaryEntry *bandwidth = av_dict_get(stream->metadata, BANDWIDTH, NULL, 0); + if (!irange || cues_start == NULL || cues_end == NULL || filename == NULL || + !bandwidth) { + return -1; + } + avio_printf(s->pb, "pb, " bandwidth=\"%s\"", bandwidth->value); + if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO && output_width) + avio_printf(s->pb, " width=\"%d\"", stream->codec->width); + if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO && output_height) + avio_printf(s->pb, " height=\"%d\"", stream->codec->height); + if (stream->codec->codec_type = AVMEDIA_TYPE_AUDIO && output_sample_rate) + avio_printf(s->pb, " audioSamplingRate=\"%d\"", stream->codec->sample_rate); + avio_printf(s->pb, ">\n"); + avio_printf(s->pb, "%s\n", filename->value); + avio_printf(s->pb, "pb, " indexRange=\"%s-%s\">\n", cues_start->value, cues_end->value); + avio_printf(s->pb, "pb, " range=\"0-%s\" />\n", irange->value); + avio_printf(s->pb, "\n"); + avio_printf(s->pb, "\n"); + return 0; +} + +/* + * Checks if width of all streams are the same. Returns 1 if true, 0 otherwise. + */ +static int check_matching_width(AVFormatContext *s, AdaptationSet *as) { + int first_width, i; + if (as->nb_streams < 2) return 1; + first_width = s->streams[as->streams[0]]->codec->width; + for (i = 1; i < as->nb_streams; i++) + if (first_width != s->streams[as->streams[i]]->codec->width) + return 0; + return 1; +} + +/* + * Checks if height of all streams are the same. Returns 1 if true, 0 otherwise. + */ +static int check_matching_height(AVFormatContext *s, AdaptationSet *as) { + int first_height, i; + if (as->nb_streams < 2) return 1; + first_height = s->streams[as->streams[0]]->codec->height; + for (i = 1; i < as->nb_streams; i++) + if (first_height != s->streams[as->streams[i]]->codec->height) + return 0; + return 1; +} + +/* + * Checks if sample rate of all streams are the same. Returns 1 if true, 0 otherwise. + */ +static int check_matching_sample_rate(AVFormatContext *s, AdaptationSet *as) { + int first_sample_rate, i; + if (as->nb_streams < 2) return 1; + first_sample_rate = s->streams[as->streams[0]]->codec->sample_rate; + for (i = 1; i < as->nb_streams; i++) + if (first_sample_rate != s->streams[as->streams[i]]->codec->sample_rate) + return 0; + return 1; +} + /* * Writes an Adaptation Set. Returns 0 on success and < 0 on failure. */ @@ -140,10 +215,22 @@ static int write_adaptation_set(AVFormatContext *s, int as_index) WebMDashMuxContext *w = s->priv_data; AdaptationSet *as = &w->as[as_index]; AVCodecContext *codec = s->streams[as->streams[0]]->codec; + AVDictionaryEntry *lang; int i; static const char boolean[2][6] = { "false", "true" }; int subsegmentStartsWithSAP = 1; - AVDictionaryEntry *lang; + + // Width, Height and Sample Rate will go in the AdaptationSet tag if they + // are the same for all contained Representations. otherwise, they will go + // on their respective Representation tag. + int width_in_as = 1, height_in_as = 1, sample_rate_in_as = 1; + if (codec->codec_type == AVMEDIA_TYPE_VIDEO) { + width_in_as = check_matching_width(s, as); + height_in_as = check_matching_height(s, as); + } else { + sample_rate_in_as = check_matching_sample_rate(s, as); + } + avio_printf(s->pb, "id); avio_printf(s->pb, " mimeType=\"%s/webm\"", codec->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio"); @@ -152,12 +239,12 @@ static int write_adaptation_set(AVFormatContext *s, int as_index) lang = av_dict_get(s->streams[as->streams[0]]->metadata, "language", NULL, 0); if (lang) avio_printf(s->pb, " lang=\"%s\"", lang->value); - if (codec->codec_type == AVMEDIA_TYPE_VIDEO) { + if (codec->codec_type == AVMEDIA_TYPE_VIDEO && width_in_as) avio_printf(s->pb, " width=\"%d\"", codec->width); + if (codec->codec_type == AVMEDIA_TYPE_VIDEO && height_in_as) avio_printf(s->pb, " height=\"%d\"", codec->height); - } else { + if (codec->codec_type == AVMEDIA_TYPE_AUDIO && sample_rate_in_as) avio_printf(s->pb, " audioSamplingRate=\"%d\"", codec->sample_rate); - } avio_printf(s->pb, " bitstreamSwitching=\"%s\"", boolean[bitstream_switching(s, as)]); @@ -173,26 +260,8 @@ static int write_adaptation_set(AVFormatContext *s, int as_index) avio_printf(s->pb, ">\n"); for (i = 0; i < as->nb_streams; i++) { - AVStream *stream = s->streams[as->streams[i]]; - AVDictionaryEntry *irange = av_dict_get(stream->metadata, INITIALIZATION_RANGE, NULL, 0); - AVDictionaryEntry *cues_start = av_dict_get(stream->metadata, CUES_START, NULL, 0); - AVDictionaryEntry *cues_end = av_dict_get(stream->metadata, CUES_END, NULL, 0); - AVDictionaryEntry *filename = av_dict_get(stream->metadata, FILENAME, NULL, 0); - AVDictionaryEntry *bandwidth = av_dict_get(stream->metadata, BANDWIDTH, NULL, 0); - if (!irange || cues_start == NULL || cues_end == NULL || filename == NULL || - !bandwidth) { - return -1; - } - avio_printf(s->pb, "pb, " bandwidth=\"%s\"", bandwidth->value); - avio_printf(s->pb, ">\n"); - avio_printf(s->pb, "%s\n", filename->value); - avio_printf(s->pb, "pb, " indexRange=\"%s-%s\">\n", cues_start->value, cues_end->value); - avio_printf(s->pb, "pb, " range=\"0-%s\" />\n", irange->value); - avio_printf(s->pb, "\n"); - avio_printf(s->pb, "\n"); + write_representation(s, s->streams[as->streams[i]], w->representation_id++, + !width_in_as, !height_in_as, !sample_rate_in_as); } avio_printf(s->pb, "\n"); return 0;