From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.ffmpeg.org (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTPS id C5D344B797 for ; Wed, 24 Sep 2025 10:36:19 +0000 (UTC) Authentication-Results: ffbox; dkim=fail (body hash mismatch (got b'xjiMEOCOQChntpOpVD34ksZCdQIclo9STc8ZSrL1UDU=', expected b'9XQSahBfccMbp79kQrlv+QbhkhRNPsV5byepalVB+KY=')) header.d=ffmpeg.org header.i=@ffmpeg.org header.a=rsa-sha256 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ffmpeg.org; i=@ffmpeg.org; q=dns/txt; s=mail; t=1758710165; h=mime-version : to : date : message-id : reply-to : subject : list-id : list-archive : list-archive : list-help : list-owner : list-post : list-subscribe : list-unsubscribe : from : cc : content-type : content-transfer-encoding : from; bh=xjiMEOCOQChntpOpVD34ksZCdQIclo9STc8ZSrL1UDU=; b=PONtcyiaWzBkiYE8jrvXsx9al2Xg8JcLCjhqzKoFC1tG9qmIT6AAxtiLhoWHZg/xskPoD QSoWirXDtdk8wXYsphZCnq58yK/12mYtDXjsUBkbL1KMjR8AtdYGEAwBauePDvB9Ffkgnip kxeNKBpc6SRgtp19/4K7r1Gxbkij97rNrTx9iSB/nj70E3lSfmlIdJKksbvEw1o9Hb9u3ul dfcM587dll936UGzcrWLQey8jOQSLSpDOHJoxm7sn3rSUHgK9rMIwJj7r23vd46LZBn8CkF No5hZHzBCW+OEXC4PcWt4Oyv6aGuqili3spDjpkd74eUp5n1xJOwZ8kMOBqw== Received: from [172.19.0.4] (unknown [172.19.0.4]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTP id 8FB7768EC89; Wed, 24 Sep 2025 13:36:05 +0300 (EEST) ARC-Seal: i=1; cv=none; a=rsa-sha256; d=ffmpeg.org; s=arc; t=1758710161; b=aA7J3Gf44JJAdV7CA1ukh5EHgbUCMPwQ4rD10T5asZRXJDaRsWb9SgDxUYhIo3BQ6qA5p AerJQrF3d0NzIYQzDM1vc/p4S/xPdieVd71o7Q5i8StyoX9CxmIpbQ0/GCC6gQi0lL4VYtL eIUIQ6AxaFg7Rtq6+wCn5v0DjdeWZIp4xMsr4TnO925QHKPYuQjqwLHn2TOuoLJyG9sqfEg xi1hPmseSJldifVlTKVv2Up6P1aPFK6AbrijD+OHMlRcrisX2fGyCuPFCKr29GpDQFXMu6f FwCdw6XZe4yxOyGXRVF9aANqk/XeUB8QL5CjCYVqfoywczs1aCJxJUSPD1mQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=ffmpeg.org; s=arc; t=1758710161; h=from : sender : reply-to : subject : date : message-id : to : cc : mime-version : content-type : content-transfer-encoding : content-id : content-description : resent-date : resent-from : resent-sender : resent-to : resent-cc : resent-message-id : in-reply-to : references : list-id : list-help : list-unsubscribe : list-subscribe : list-post : list-owner : list-archive; bh=PIYPinb5MsdqIfRmoEz6MUec6NVHcWPnVchgeiHIGKc=; b=X7e3yOc3g4kC1+l0Kj3kwwDoOfAnnrFhwx/Ljom/F2fwIr+blSqWn80KQqNMLXtK7vS3e yDGq7HmHBnRxccN/r0DwtnqGY/oDWvdFRcEnz1Fo7ioEmXNb/78NmnxHDCrT9qgN2N3mu+Q 6Wfijdhk+ADdQc14Faz+qGKx6sLnR6wGyzFI5nS/4vrICoyfRH3RnbWIuAwimlitOT3N9VB vPLeMlAqIlMILP4anJX05DxfbYB9Mh6QEe00DWWDGWSObQq2BnHtvuGwLwU6G2Ult1KW7GN cYNV0hFGZnRb056qY3HqV5gKuzyr/2AJwJZZPZrXkMGtxi+P9ZMD/gs3Ddmw== ARC-Authentication-Results: i=1; ffmpeg.org; dkim=pass header.d=ffmpeg.org header.i=@ffmpeg.org; arc=none; dmarc=pass header.from=ffmpeg.org policy.dmarc=quarantine Authentication-Results: ffmpeg.org; dkim=pass header.d=ffmpeg.org header.i=@ffmpeg.org; arc=none (Message is not ARC signed); dmarc=pass (Used From Domain Record) header.from=ffmpeg.org policy.dmarc=quarantine DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ffmpeg.org; i=@ffmpeg.org; q=dns/txt; s=mail; t=1758710153; h=content-type : mime-version : content-transfer-encoding : from : to : reply-to : subject : date : from; bh=9XQSahBfccMbp79kQrlv+QbhkhRNPsV5byepalVB+KY=; b=aXRNwQGqTwPAL4KNhMOqKkbYZ+AFrJKd6oGb5ihyQfZfzgR6WpLNOIFOEw96mAPUOrnjz DlhE/HfaUaH81BoZdZegKBz3QWs1XaY/6u9NNeNT1r8IcsKeDV9iG+Knym7pNou/YyA4Do+ 9hwEoZ4+vxDfYzsXMa12LnyHWdIUTPheWEqEzToX5JtvQ968jlW3ccqvVej7yU/0rXZIY5m pxZwhz63v2HX837g3IMJYpC49F+uP4aBYPh+5cAKIfWt0CDKgFxJ3V70g2K6E850bCQ+BDq 9jZkuSJn1Hv44g/MvrzJDoxtZ+/5dZnUylLGEWyWVrPUJQ7Y+AjvjWKgaCwQ== Received: from ed19c606a818 (code.ffmpeg.org [188.245.149.3]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTPS id 4B64B68EA1F for ; Wed, 24 Sep 2025 13:35:53 +0300 (EEST) MIME-Version: 1.0 To: ffmpeg-devel@ffmpeg.org Date: Wed, 24 Sep 2025 10:35:52 -0000 Message-ID: <175871015359.25.174754706555283060@bf249f23a2c8> Message-ID-Hash: HJYXS7F7KSZZELE74O6M36T3R7P5JWLB X-Message-ID-Hash: HJYXS7F7KSZZELE74O6M36T3R7P5JWLB X-MailFrom: code@ffmpeg.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-ffmpeg-devel.ffmpeg.org-0; header-match-ffmpeg-devel.ffmpeg.org-1; header-match-ffmpeg-devel.ffmpeg.org-2; header-match-ffmpeg-devel.ffmpeg.org-3; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list Reply-To: FFmpeg development discussions and patches Subject: [FFmpeg-devel] [PATCH] libavformat/dashenc: preserve metadata from container and streams (PR #20594) List-Id: FFmpeg development discussions and patches Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: damitha via ffmpeg-devel Cc: damitha Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Archived-At: List-Archive: List-Post: PR #20594 opened by damitha URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20594 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20594.patch Currently metadata is dropped at the container and stream level when dash muxer is used. This is fixing that >>From 7b3b20a1e8719ff922e509623f3763af3574c9ff Mon Sep 17 00:00:00 2001 From: Damitha Gunawardena Date: Wed, 24 Sep 2025 20:12:31 +1000 Subject: [PATCH 1/2] preserve metadata in dashenc --- libavformat/dashenc.c | 621 ++++++++++++++++++++++++++---------------- 1 file changed, 382 insertions(+), 239 deletions(-) diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index af92e38bbd..7ca46e201a 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -123,10 +123,10 @@ typedef struct OutputStream { int last_flags; int bit_rate; int first_segment_bit_rate; - SegmentType segment_type; /* segment type selected for this particular stream */ + SegmentType segment_type; /* segment type selected for this particular stream */ const char *format_name; const char *extension_name; - const char *single_file_name; /* file names selected for this particular stream */ + const char *single_file_name; /* file names selected for this particular stream */ const char *init_seg_name; const char *media_seg_name; @@ -148,7 +148,7 @@ typedef struct OutputStream { } OutputStream; typedef struct DASHContext { - const AVClass *class; /* Class for private options. */ + const AVClass *class; /* Class for private options. */ char *adaptation_sets; AdaptationSet *as; int nb_as; @@ -168,7 +168,7 @@ typedef struct DASHContext { time_t start_time_s; int64_t presentation_time_offset; char dirname[1024]; - const char *single_file_name; /* file names as specified in options */ + const char *single_file_name; /* file names as specified in options */ const char *init_seg_name; const char *media_seg_name; const char *utc_timing_url; @@ -187,7 +187,7 @@ typedef struct DASHContext { int index_correction; AVDictionary *format_options; int global_sidx; - SegmentType segment_type_option; /* segment type as specified in options */ + SegmentType segment_type_option; /* segment type as specified in options */ int ignore_io_errors; int lhls; int ldash; @@ -210,12 +210,12 @@ static const struct codec_string { enum AVCodecID id; const char str[8]; } codecs[] = { - { AV_CODEC_ID_VP8, "vp8" }, - { AV_CODEC_ID_VP9, "vp9" }, - { AV_CODEC_ID_VORBIS, "vorbis" }, - { AV_CODEC_ID_OPUS, "opus" }, - { AV_CODEC_ID_FLAC, "flac" }, - { AV_CODEC_ID_NONE } + {AV_CODEC_ID_VP8, "vp8"}, + {AV_CODEC_ID_VP9, "vp9"}, + {AV_CODEC_ID_VORBIS, "vorbis"}, + {AV_CODEC_ID_OPUS, "opus"}, + {AV_CODEC_ID_FLAC, "flac"}, + {AV_CODEC_ID_NONE} }; static int dashenc_io_open(AVFormatContext *s, AVIOContext **pb, char *filename, @@ -256,22 +256,19 @@ static void dashenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filenam } } -static const char *get_format_str(SegmentType segment_type) -{ +static const char *get_format_str(SegmentType segment_type) { switch (segment_type) { - case SEGMENT_TYPE_MP4: return "mp4"; - case SEGMENT_TYPE_WEBM: return "webm"; + case SEGMENT_TYPE_MP4: return "mp4"; + case SEGMENT_TYPE_WEBM: return "webm"; } return NULL; } -static const char *get_extension_str(SegmentType type, int single_file) -{ +static const char *get_extension_str(SegmentType type, int single_file) { switch (type) { - - case SEGMENT_TYPE_MP4: return single_file ? "mp4" : "m4s"; - case SEGMENT_TYPE_WEBM: return "webm"; - default: return NULL; + case SEGMENT_TYPE_MP4: return single_file ? "mp4" : "m4s"; + case SEGMENT_TYPE_WEBM: return "webm"; + default: return NULL; } } @@ -282,8 +279,7 @@ static int handle_io_open_error(AVFormatContext *s, int err, char *url) { return c->ignore_io_errors ? 0 : err; } -static inline SegmentType select_segment_type(SegmentType segment_type, enum AVCodecID codec_id) -{ +static inline SegmentType select_segment_type(SegmentType segment_type, enum 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) { @@ -296,8 +292,7 @@ static inline SegmentType select_segment_type(SegmentType segment_type, enum AVC return segment_type; } -static int init_segment_types(AVFormatContext *s) -{ +static int init_segment_types(AVFormatContext *s) { DASHContext *c = s->priv_data; int has_mp4_streams = 0; for (int i = 0; i < s->nb_streams; ++i) { @@ -320,8 +315,8 @@ static int init_segment_types(AVFormatContext *s) } if (c->hls_playlist && !has_mp4_streams) { - av_log(s, AV_LOG_WARNING, "No mp4 streams, disabling HLS manifest generation\n"); - c->hls_playlist = 0; + av_log(s, AV_LOG_WARNING, "No mp4 streams, disabling HLS manifest generation\n"); + c->hls_playlist = 0; } return 0; @@ -343,9 +338,8 @@ static void set_vp9_codec_str(AVFormatContext *s, AVCodecParameters *par, } static void set_codec_str(AVFormatContext *s, AVCodecParameters *par, - AVRational *frame_rate, char *str, int size) -{ - const AVCodecTag *tags[2] = { NULL, NULL }; + AVRational *frame_rate, char *str, int size) { + const AVCodecTag *tags[2] = {NULL, NULL}; uint32_t tag; int i; @@ -438,8 +432,7 @@ static void set_codec_str(AVFormatContext *s, AVCodecParameters *par, } } -static int flush_dynbuf(DASHContext *c, OutputStream *os, int *range_length) -{ +static int flush_dynbuf(DASHContext *c, OutputStream *os, int *range_length) { uint8_t *buffer; if (!os->ctx->pb) { @@ -467,8 +460,7 @@ static int flush_dynbuf(DASHContext *c, OutputStream *os, int *range_length) } } -static void set_http_options(AVDictionary **options, DASHContext *c) -{ +static void set_http_options(AVDictionary **options, DASHContext *c) { if (c->method) av_dict_set(options, "method", c->method, 0); av_dict_copy(options, c->http_opts, 0); @@ -493,7 +485,7 @@ static void get_start_index_number(OutputStream *os, DASHContext *c, *start_index = 0; *start_number = 1; if (c->window_size) { - *start_index = FFMAX(os->nb_segments - c->window_size, 0); + *start_index = FFMAX(os->nb_segments - c->window_size, 0); *start_number = FFMAX(os->segment_index - c->window_size, 1); } } @@ -556,10 +548,10 @@ static void write_hls_media_playlist(OutputStream *os, AVFormatContext *s, seg->prog_date_time = prog_date_time; ret = ff_hls_write_file_entry(c->m3u8_out, 0, c->single_file, - (double) seg->duration / timescale, 0, - seg->range_length, seg->start_pos, NULL, - c->single_file ? os->initfile : seg->file, - &prog_date_time, 0, 0, 0); + (double) seg->duration / timescale, 0, + seg->range_length, seg->start_pos, NULL, + c->single_file ? os->initfile : seg->file, + &prog_date_time, 0, 0, 0); if (ret < 0) { av_log(os->ctx, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); } @@ -577,8 +569,7 @@ static void write_hls_media_playlist(OutputStream *os, AVFormatContext *s, ff_rename(temp_filename_hls, filename_hls, os->ctx); } -static int flush_init_segment(AVFormatContext *s, OutputStream *os) -{ +static int flush_init_segment(AVFormatContext *s, OutputStream *os) { DASHContext *c = s->priv_data; int ret, range_length; @@ -595,8 +586,7 @@ static int flush_init_segment(AVFormatContext *s, OutputStream *os) return 0; } -static void dash_free(AVFormatContext *s) -{ +static void dash_free(AVFormatContext *s) { DASHContext *c = s->priv_data; int i, j; @@ -638,8 +628,7 @@ static void dash_free(AVFormatContext *s) } static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatContext *s, - int representation_id, int final) -{ + int representation_id, int final) { DASHContext *c = s->priv_data; int i, start_index, start_number; get_start_index_number(os, c, &start_index, &start_number); @@ -656,14 +645,15 @@ static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatCont if (c->streaming && os->availability_time_offset && !final) avio_printf(out, "availabilityTimeComplete=\"false\" "); - avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\"", os->init_seg_name, os->media_seg_name, c->use_timeline ? start_number : 1); + avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\"", os->init_seg_name, os->media_seg_name, + c->use_timeline ? start_number : 1); if (c->presentation_time_offset) avio_printf(out, " presentationTimeOffset=\"%"PRId64"\"", c->presentation_time_offset); avio_printf(out, ">\n"); if (c->use_timeline) { int64_t cur_time = 0; avio_printf(out, "\t\t\t\t\t\n"); - for (i = start_index; i < os->nb_segments; ) { + for (i = start_index; i < os->nb_segments;) { Segment *seg = os->segments[i]; int repeat = 0; avio_printf(out, "\t\t\t\t\t\tduration); while (i + repeat + 1 < os->nb_segments && os->segments[i + repeat + 1]->duration == seg->duration && - os->segments[i + repeat + 1]->time == os->segments[i + repeat]->time + os->segments[i + repeat]->duration) + os->segments[i + repeat + 1]->time == os->segments[i + repeat]->time + os->segments[i + repeat]-> + duration) repeat++; if (repeat > 0) avio_printf(out, "r=\"%d\" ", repeat); @@ -687,18 +678,23 @@ static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatCont avio_printf(out, "\t\t\t\t\n"); } else if (c->single_file) { avio_printf(out, "\t\t\t\t%s\n", os->initfile); - avio_printf(out, "\t\t\t\t\n", AV_TIME_BASE, FFMIN(os->seg_duration, os->last_duration), start_number); - avio_printf(out, "\t\t\t\t\t\n", os->init_start_pos, os->init_start_pos + os->init_range_length - 1); + avio_printf(out, "\t\t\t\t\n", + AV_TIME_BASE, FFMIN(os->seg_duration, os->last_duration), start_number); + avio_printf(out, "\t\t\t\t\t\n", os->init_start_pos, + os->init_start_pos + os->init_range_length - 1); for (i = start_index; i < os->nb_segments; i++) { Segment *seg = os->segments[i]; - avio_printf(out, "\t\t\t\t\tstart_pos, seg->start_pos + seg->range_length - 1); + avio_printf(out, "\t\t\t\t\tstart_pos, + seg->start_pos + seg->range_length - 1); if (seg->index_length) - avio_printf(out, "indexRange=\"%"PRId64"-%"PRId64"\" ", seg->start_pos, seg->start_pos + seg->index_length - 1); + avio_printf(out, "indexRange=\"%"PRId64"-%"PRId64"\" ", seg->start_pos, + seg->start_pos + seg->index_length - 1); avio_printf(out, "/>\n"); } avio_printf(out, "\t\t\t\t\n"); } else { - avio_printf(out, "\t\t\t\t\n", AV_TIME_BASE, FFMIN(os->seg_duration, os->last_duration), start_number); + avio_printf(out, "\t\t\t\t\n", + AV_TIME_BASE, FFMIN(os->seg_duration, os->last_duration), start_number); avio_printf(out, "\t\t\t\t\t\n", os->initfile); for (i = start_index; i < os->nb_segments; i++) { Segment *seg = os->segments[i]; @@ -709,11 +705,10 @@ static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatCont if (!c->lhls || final) { write_hls_media_playlist(os, s, representation_id, final, NULL); } - } static char *xmlescape(const char *str) { - int outlen = strlen(str)*3/2 + 6; + int outlen = strlen(str) * 3 / 2 + 6; char *out = av_realloc(NULL, outlen + 1); int pos = 0; if (!out) @@ -752,8 +747,7 @@ static char *xmlescape(const char *str) { return out; } -static void write_time(AVIOContext *out, int64_t time) -{ +static void write_time(AVIOContext *out, int64_t time) { int seconds = time / AV_TIME_BASE; int fractions = time % AV_TIME_BASE; int minutes = seconds / 60; @@ -768,8 +762,7 @@ static void write_time(AVIOContext *out, int64_t time) avio_printf(out, "%d.%dS", seconds, fractions / (AV_TIME_BASE / 10)); } -static void format_date(char *buf, int size, int64_t time_us) -{ +static void format_date(char *buf, int size, int64_t time_us) { struct tm *ptm, tmbuf; int64_t time_ms = time_us / 1000; const time_t time_s = time_ms / 1000; @@ -787,18 +780,21 @@ static void format_date(char *buf, int size, int64_t time_us) } static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_index, - int final) -{ + int final) { DASHContext *c = s->priv_data; AdaptationSet *as = &c->as[as_index]; AVDictionaryEntry *lang, *role; int i; - avio_printf(out, "\t\tid, as->media_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio"); - if (as->media_type == AVMEDIA_TYPE_VIDEO && as->max_frame_rate.num && !as->ambiguous_frame_rate && av_cmp_q(as->min_frame_rate, as->max_frame_rate) < 0) + avio_printf( + out, + "\t\tid, as->media_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio"); + if (as->media_type == AVMEDIA_TYPE_VIDEO && as->max_frame_rate.num && !as->ambiguous_frame_rate && av_cmp_q( + as->min_frame_rate, as->max_frame_rate) < 0) avio_printf(out, " maxFrameRate=\"%d/%d\"", as->max_frame_rate.num, as->max_frame_rate.den); - else if (as->media_type == AVMEDIA_TYPE_VIDEO && as->max_frame_rate.num && !as->ambiguous_frame_rate && !av_cmp_q(as->min_frame_rate, as->max_frame_rate)) + else if (as->media_type == AVMEDIA_TYPE_VIDEO && as->max_frame_rate.num && !as->ambiguous_frame_rate && !av_cmp_q( + as->min_frame_rate, as->max_frame_rate)) avio_printf(out, " frameRate=\"%d/%d\"", as->max_frame_rate.num, as->max_frame_rate.den); if (as->media_type == AVMEDIA_TYPE_VIDEO) { avio_printf(out, " maxWidth=\"%d\" maxHeight=\"%d\"", as->max_width, as->max_height); @@ -812,7 +808,10 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind if (!final && c->ldash && as->max_frag_duration && !(c->profile & MPD_PROFILE_DVB)) avio_printf(out, "\t\t\t\n", as->max_frag_duration); if (as->trick_idx >= 0) - avio_printf(out, "\t\t\t\n", as->id, as->trick_idx); + avio_printf( + out, + "\t\t\t\n", + as->id, as->trick_idx); role = av_dict_get(as->metadata, "role", NULL, 0); if (role) avio_printf(out, "\t\t\t\n", role->value); @@ -835,8 +834,10 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"", os->first_segment_bit_rate); if (as->media_type == AVMEDIA_TYPE_VIDEO) { - avio_printf(out, "\t\t\tformat_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height); + avio_printf( + out, "\t\t\tformat_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, + s->streams[i]->codecpar->height); if (st->codecpar->field_order == AV_FIELD_UNKNOWN) avio_printf(out, " scanType=\"unknown\""); else if (st->codecpar->field_order != AV_FIELD_PROGRESSIVE) @@ -847,21 +848,31 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind if (as->trick_idx >= 0) { AdaptationSet *tas = &c->as[as->trick_idx]; if (!as->ambiguous_frame_rate && !tas->ambiguous_frame_rate) - avio_printf(out, " maxPlayoutRate=\"%d\"", FFMAX((int)av_q2d(av_div_q(tas->min_frame_rate, as->min_frame_rate)), 1)); + avio_printf(out, " maxPlayoutRate=\"%d\"", + FFMAX((int)av_q2d(av_div_q(tas->min_frame_rate, as->min_frame_rate)), 1)); } if (!os->coding_dependency) avio_printf(out, " codingDependency=\"false\""); avio_printf(out, ">\n"); } else { - avio_printf(out, "\t\t\t\n", + avio_printf( + out, + "\t\t\t\n", i, os->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->sample_rate); - avio_printf(out, "\t\t\t\t\n", + avio_printf( + out, + "\t\t\t\t\n", s->streams[i]->codecpar->ch_layout.nb_channels); } if (!final && c->write_prft && os->producer_reference_time_str[0]) { - avio_printf(out, "\t\t\t\t\n", - i, os->producer_reference_time.flags ? "captured" : "encoder", os->producer_reference_time_str, c->presentation_time_offset); - avio_printf(out, "\t\t\t\t\t\n", c->utc_timing_url); + avio_printf( + out, + "\t\t\t\t\n", + i, os->producer_reference_time.flags ? "captured" : "encoder", os->producer_reference_time_str, + c->presentation_time_offset); + avio_printf(out, "\t\t\t\t\t\n", + c->utc_timing_url); avio_printf(out, "\t\t\t\t\n"); } if (!final && c->ldash && os->gop_size && os->frag_type != FRAG_TYPE_NONE && !(c->profile & MPD_PROFILE_DVB) && @@ -875,8 +886,7 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind return 0; } -static int add_adaptation_set(AVFormatContext *s, AdaptationSet **as, enum AVMediaType type) -{ +static int add_adaptation_set(AVFormatContext *s, AdaptationSet **as, enum AVMediaType type) { DASHContext *c = s->priv_data; void *mem; @@ -899,8 +909,7 @@ static int add_adaptation_set(AVFormatContext *s, AdaptationSet **as, enum AVMed return 0; } -static int adaptation_set_add_stream(AVFormatContext *s, int as_idx, int i) -{ +static int adaptation_set_add_stream(AVFormatContext *s, int as_idx, int i) { DASHContext *c = s->priv_data; AdaptationSet *as = &c->as[as_idx - 1]; OutputStream *os = &c->streams[i]; @@ -922,8 +931,7 @@ static int adaptation_set_add_stream(AVFormatContext *s, int as_idx, int i) return 0; } -static int parse_adaptation_sets(AVFormatContext *s) -{ +static int parse_adaptation_sets(AVFormatContext *s) { DASHContext *c = s->priv_data; const char *p = c->adaptation_sets; enum { new_set, parse_default, parsing_streams, parse_seg_duration, parse_frag_duration } state; @@ -1049,7 +1057,8 @@ static int parse_adaptation_sets(AVFormatContext *s) if (*p) p++; state = parse_default; - } else if ((state != new_set) && av_strstart(p, "streams=", &p)) { //descriptor and durations are optional + } else if ((state != new_set) && av_strstart(p, "streams=", &p)) { + //descriptor and durations are optional state = parsing_streams; } else if (state == parsing_streams) { AdaptationSet *as = &c->as[c->nb_as - 1]; @@ -1073,7 +1082,8 @@ static int parse_adaptation_sets(AVFormatContext *s) if ((ret = adaptation_set_add_stream(s, c->nb_as, i)) < 0) return ret; } - } else { // select single stream + } else { + // select single stream i = strtol(idx_str, &end_str, 10); if (idx_str == end_str || i < 0 || i >= s->nb_streams) { av_log(s, AV_LOG_ERROR, "Selected stream \"%s\" not found!\n", idx_str); @@ -1118,7 +1128,9 @@ end: break; } if (n >= c->nb_as) { - av_log(s, AV_LOG_ERROR, "reference AdaptationSet id \"%d\" not found for trick mode AdaptationSet id \"%d\"\n", as->trick_idx, as->id); + av_log(s, AV_LOG_ERROR, + "reference AdaptationSet id \"%d\" not found for trick mode AdaptationSet id \"%d\"\n", + as->trick_idx, as->id); return AVERROR(EINVAL); } } @@ -1126,8 +1138,7 @@ end: return 0; } -static int write_manifest(AVFormatContext *s, int final) -{ +static int write_manifest(AVFormatContext *s, int final) { DASHContext *c = s->priv_data; AVIOContext *out; char temp_filename[1024]; @@ -1139,7 +1150,8 @@ static int write_manifest(AVFormatContext *s, int final) AVDictionary *opts = NULL; if (!use_rename && !warned_non_file++) - av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n"); + av_log(s, AV_LOG_ERROR, + "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n"); snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->url); set_http_options(&opts, c); @@ -1156,9 +1168,9 @@ static int write_manifest(AVFormatContext *s, int final) "\txsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd\"\n" "\tprofiles=\""); if (c->profile & MPD_PROFILE_DASH) - avio_printf(out, "%s%s", "urn:mpeg:dash:profile:isoff-live:2011", c->profile & MPD_PROFILE_DVB ? "," : "\"\n"); + avio_printf(out, "%s%s", "urn:mpeg:dash:profile:isoff-live:2011", c->profile & MPD_PROFILE_DVB ? "," : "\"\n"); if (c->profile & MPD_PROFILE_DVB) - avio_printf(out, "%s", "urn:dvb:dash:profile:dvb-dash:2014\"\n"); + avio_printf(out, "%s", "urn:dvb:dash:profile:dvb-dash:2014\"\n"); avio_printf(out, "\ttype=\"%s\"\n", final ? "static" : "dynamic"); if (final) { @@ -1207,8 +1219,8 @@ static int write_manifest(AVFormatContext *s, int final) avio_printf(out, " referenceId=\"%d\"", c->target_latency_refid); avio_printf(out, "/>\n"); } - if (av_cmp_q(c->min_playback_rate, (AVRational) {1, 1}) || - av_cmp_q(c->max_playback_rate, (AVRational) {1, 1})) + if (av_cmp_q(c->min_playback_rate, (AVRational){1, 1}) || + av_cmp_q(c->max_playback_rate, (AVRational){1, 1})) avio_printf(out, "\t\t\n", av_q2d(c->min_playback_rate), av_q2d(c->max_playback_rate)); avio_printf(out, "\t\n"); @@ -1231,7 +1243,8 @@ static int write_manifest(AVFormatContext *s, int final) avio_printf(out, "\t\n"); if (c->utc_timing_url) - avio_printf(out, "\t\n", c->utc_timing_url); + avio_printf(out, "\t\n", + c->utc_timing_url); avio_printf(out, "\n"); avio_flush(out); @@ -1247,7 +1260,7 @@ static int write_manifest(AVFormatContext *s, int final) // Publish master playlist only the configured rate if (c->master_playlist_created && (!c->master_publish_rate || - c->streams[0].segment_index % c->master_publish_rate)) + c->streams[0].segment_index % c->master_publish_rate)) return 0; if (*c->dirname) @@ -1324,7 +1337,6 @@ static int write_manifest(AVFormatContext *s, int final) playlist_file, agroup, codec_str, NULL, NULL); } - } else { // treat audio streams as separate renditions @@ -1362,16 +1374,14 @@ static int write_manifest(AVFormatContext *s, int final) return 0; } -static int dict_copy_entry(AVDictionary **dst, const AVDictionary *src, const char *key) -{ +static int dict_copy_entry(AVDictionary **dst, const AVDictionary *src, const char *key) { AVDictionaryEntry *entry = av_dict_get(src, key, NULL, 0); if (entry) av_dict_set(dst, key, entry->value, AV_DICT_DONT_OVERWRITE); return 0; } -static int dash_init(AVFormatContext *s) -{ +static int dash_init(AVFormatContext *s) { DASHContext *c = s->priv_data; int ret = 0, i; char *ptr; @@ -1434,27 +1444,31 @@ static int dash_init(AVFormatContext *s) } if (c->write_prft && !c->utc_timing_url) { - av_log(s, AV_LOG_WARNING, "Producer Reference Time element option will be ignored as utc_timing_url is not set\n"); + av_log(s, AV_LOG_WARNING, + "Producer Reference Time element option will be ignored as utc_timing_url is not set\n"); c->write_prft = 0; } if (c->write_prft && !c->streaming) { - av_log(s, AV_LOG_WARNING, "Producer Reference Time element option will be ignored as streaming is not enabled\n"); + av_log(s, AV_LOG_WARNING, + "Producer Reference Time element option will be ignored as streaming is not enabled\n"); c->write_prft = 0; } if (c->ldash && !c->write_prft) { - av_log(s, AV_LOG_WARNING, "Low Latency mode enabled without Producer Reference Time element option! Resulting manifest may not be complaint\n"); + av_log(s, AV_LOG_WARNING, + "Low Latency mode enabled without Producer Reference Time element option! Resulting manifest may not be complaint\n"); } if (c->target_latency && !c->write_prft) { - av_log(s, AV_LOG_WARNING, "Target latency option will be ignored as Producer Reference Time element will not be written\n"); + av_log(s, AV_LOG_WARNING, + "Target latency option will be ignored as Producer Reference Time element will not be written\n"); c->target_latency = 0; } if (av_cmp_q(c->max_playback_rate, c->min_playback_rate) < 0) { av_log(s, AV_LOG_WARNING, "Minimum playback rate value is higher than the Maximum. Both will be ignored\n"); - c->min_playback_rate = c->max_playback_rate = (AVRational) {1, 1}; + c->min_playback_rate = c->max_playback_rate = (AVRational){1, 1}; } av_strlcpy(c->dirname, s->url, sizeof(c->dirname)); @@ -1491,8 +1505,7 @@ static int dash_init(AVFormatContext *s) os->bit_rate = s->streams[i]->codecpar->bit_rate; if (!os->bit_rate) { - int level = s->strict_std_compliance >= FF_COMPLIANCE_STRICT ? - AV_LOG_ERROR : AV_LOG_WARNING; + int level = s->strict_std_compliance >= FF_COMPLIANCE_STRICT ? AV_LOG_ERROR : AV_LOG_WARNING; av_log(s, level, "No bit rate set for stream %d\n", i); if (s->strict_std_compliance >= FF_COMPLIANCE_STRICT) return AVERROR(EINVAL); @@ -1519,9 +1532,9 @@ static int dash_init(AVFormatContext *s) } if (os->segment_type == SEGMENT_TYPE_WEBM) { - if ((!c->single_file && !av_match_ext(os->init_seg_name, os->format_name)) || + if ((!c->single_file && !av_match_ext(os->init_seg_name, os->format_name)) || (!c->single_file && !av_match_ext(os->media_seg_name, os->format_name)) || - ( c->single_file && !av_match_ext(os->single_file_name, os->format_name))) { + (c->single_file && !av_match_ext(os->single_file_name, os->format_name))) { 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 " @@ -1529,7 +1542,8 @@ static int dash_init(AVFormatContext *s) } if (c->streaming) { // Streaming not supported as matroskaenc buffers internally before writing the output - av_log(s, AV_LOG_WARNING, "One or more streams in WebM output format. Streaming option will be ignored\n"); + av_log(s, AV_LOG_WARNING, + "One or more streams in WebM output format. Streaming option will be ignored\n"); c->streaming = 0; } } @@ -1541,10 +1555,10 @@ static int dash_init(AVFormatContext *s) ctx->oformat = av_guess_format(os->format_name, NULL, NULL); if (!ctx->oformat) return AVERROR_MUXER_NOT_FOUND; - ctx->interrupt_callback = s->interrupt_callback; - ctx->opaque = s->opaque; - ctx->io_close2 = s->io_close2; - ctx->io_open = s->io_open; + ctx->interrupt_callback = s->interrupt_callback; + ctx->opaque = s->opaque; + ctx->io_close2 = s->io_close2; + ctx->io_open = s->io_open; ctx->strict_std_compliance = s->strict_std_compliance; if (!(st = avformat_new_stream(ctx, NULL))) @@ -1570,7 +1584,8 @@ static int dash_init(AVFormatContext *s) if (c->single_file) { if (os->single_file_name) - ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), os->single_file_name, i, 0, os->bit_rate, 0); + ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), os->single_file_name, i, 0, os->bit_rate, + 0); else snprintf(os->initfile, sizeof(os->initfile), "%s-stream%d.%s", basename, i, os->format_name); } else { @@ -1605,7 +1620,8 @@ static int dash_init(AVFormatContext *s) c->max_segment_duration = FFMAX(c->max_segment_duration, as->seg_duration); if (c->profile & MPD_PROFILE_DVB && (os->seg_duration > 15000000 || os->seg_duration < 960000)) { - av_log(s, AV_LOG_ERROR, "Segment duration %"PRId64" is outside the allowed range for DVB-DASH profile\n", os->seg_duration); + av_log(s, AV_LOG_ERROR, "Segment duration %"PRId64" is outside the allowed range for DVB-DASH profile\n", + os->seg_duration); return AVERROR(EINVAL); } @@ -1614,12 +1630,14 @@ static int dash_init(AVFormatContext *s) os->frag_type = c->streaming ? FRAG_TYPE_EVERY_FRAME : FRAG_TYPE_NONE; } if (os->frag_type == FRAG_TYPE_DURATION && os->frag_duration > os->seg_duration) { - av_log(s, AV_LOG_ERROR, "Fragment duration %"PRId64" is longer than Segment duration %"PRId64"\n", os->frag_duration, os->seg_duration); + av_log(s, AV_LOG_ERROR, "Fragment duration %"PRId64" is longer than Segment duration %"PRId64"\n", + os->frag_duration, os->seg_duration); return AVERROR(EINVAL); } if (os->frag_type == FRAG_TYPE_PFRAMES && (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO || !os->parser)) { if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !os->parser) - av_log(s, AV_LOG_WARNING, "frag_type set to P-Frame reordering, but no parser found for stream %d\n", i); + av_log(s, AV_LOG_WARNING, "frag_type set to P-Frame reordering, but no parser found for stream %d\n", + i); os->frag_type = c->streaming ? FRAG_TYPE_EVERY_FRAME : FRAG_TYPE_NONE; } if (os->frag_type != FRAG_TYPE_PFRAMES && as->trick_idx < 0) @@ -1628,8 +1646,8 @@ static int dash_init(AVFormatContext *s) if (os->segment_type == SEGMENT_TYPE_MP4) { if (c->streaming) - // skip_sidx : Reduce bitrate overhead - // skip_trailer : Avoids growing memory usage with time + // skip_sidx : Reduce bitrate overhead + // skip_trailer : Avoids growing memory usage with time av_dict_set(&opts, "movflags", "+dash+delay_moov+skip_sidx+skip_trailer", AV_DICT_APPEND); else { if (c->global_sidx) @@ -1686,14 +1704,16 @@ static int dash_init(AVFormatContext *s) if (st->sample_aspect_ratio.num) os->sar = st->sample_aspect_ratio; else - os->sar = (AVRational){1,1}; + os->sar = (AVRational){1, 1}; av_reduce(&par.num, &par.den, - st->codecpar->width * (int64_t)os->sar.num, - st->codecpar->height * (int64_t)os->sar.den, + st->codecpar->width * (int64_t) os->sar.num, + st->codecpar->height * (int64_t) os->sar.den, 1024 * 1024); if (as->par.num && av_cmp_q(par, as->par)) { - av_log(s, AV_LOG_ERROR, "Conflicting stream aspect ratios values in Adaptation Set %d. Please ensure all adaptation sets have the same aspect ratio\n", os->as_idx); + av_log(s, AV_LOG_ERROR, + "Conflicting stream aspect ratios values in Adaptation Set %d. Please ensure all adaptation sets have the same aspect ratio\n", + os->as_idx); return AVERROR(EINVAL); } as->par = par; @@ -1712,6 +1732,7 @@ static int dash_init(AVFormatContext *s) c->nr_of_streams_to_flush++; } + if (!c->has_video && c->seg_duration <= 0) { av_log(s, AV_LOG_WARNING, "no video stream and no seg duration set\n"); return AVERROR(EINVAL); @@ -1725,15 +1746,15 @@ static int dash_init(AVFormatContext *s) return 0; } -static int dash_write_header(AVFormatContext *s) -{ +static int dash_write_header(AVFormatContext *s) { DASHContext *c = s->priv_data; int i, ret; for (i = 0; i < s->nb_streams; i++) { OutputStream *os = &c->streams[i]; + av_dict_copy(&os->ctx->metadata, s->metadata, 0); + av_dict_copy(&os->ctx->metadata, s->streams[i]->metadata, 0); if ((ret = avformat_write_header(os->ctx, NULL)) < 0) return ret; - // 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. @@ -1747,14 +1768,13 @@ static int dash_write_header(AVFormatContext *s) static int add_segment(OutputStream *os, const char *file, int64_t time, int64_t duration, int64_t start_pos, int64_t range_length, - int64_t index_length, int next_exp_index) -{ + int64_t index_length, int next_exp_index) { int err; Segment *seg; if (os->nb_segments >= os->segments_size) { os->segments_size = (os->segments_size + 1) * 2; if ((err = av_reallocp_array(&os->segments, sizeof(*os->segments), - os->segments_size)) < 0) { + os->segments_size)) < 0) { os->segments_size = 0; os->nb_segments = 0; return err; @@ -1766,7 +1786,8 @@ static int add_segment(OutputStream *os, const char *file, av_strlcpy(seg->file, file, sizeof(seg->file)); seg->time = time; seg->duration = duration; - if (seg->time < 0) { // If pts<0, it is expected to be cut away with an edit list + if (seg->time < 0) { + // If pts<0, it is expected to be cut away with an edit list seg->duration += seg->time; seg->time = 0; } @@ -1784,8 +1805,7 @@ static int add_segment(OutputStream *os, const char *file, return 0; } -static void write_styp(AVIOContext *pb) -{ +static void write_styp(AVIOContext *pb) { avio_wb32(pb, 24); ffio_wfourcc(pb, "styp"); ffio_wfourcc(pb, "msdh"); @@ -1795,8 +1815,7 @@ static void write_styp(AVIOContext *pb) } static void find_index_range(AVFormatContext *s, const char *full_path, - int64_t pos, int *index_length) -{ + int64_t pos, int *index_length) { uint8_t buf[8]; AVIOContext *pb; int ret; @@ -1818,8 +1837,7 @@ static void find_index_range(AVFormatContext *s, const char *full_path, } static int update_stream_extradata(AVFormatContext *s, OutputStream *os, - AVPacket *pkt, AVRational *frame_rate) -{ + AVPacket *pkt, AVRational *frame_rate) { AVCodecParameters *par = os->ctx->streams[0]->codecpar; uint8_t *extradata; size_t extradata_size; @@ -1864,13 +1882,12 @@ static void dashenc_delete_file(AVFormatContext *s, char *filename) { int res = ffurl_delete(filename); if (res < 0) { av_log(s, (res == AVERROR(ENOENT) ? AV_LOG_WARNING : AV_LOG_ERROR), - "failed to delete %s: %s\n", filename, av_err2str(res)); + "failed to delete %s: %s\n", filename, av_err2str(res)); } } } -static int dashenc_delete_segment_file(AVFormatContext *s, const char* file) -{ +static int dashenc_delete_segment_file(AVFormatContext *s, const char *file) { DASHContext *c = s->priv_data; AVBPrint buf; @@ -1889,8 +1906,7 @@ static int dashenc_delete_segment_file(AVFormatContext *s, const char* file) return 0; } -static inline void dashenc_delete_media_segments(AVFormatContext *s, OutputStream *os, int remove_count) -{ +static inline void dashenc_delete_media_segments(AVFormatContext *s, OutputStream *os, int remove_count) { for (int i = 0; i < remove_count; ++i) { dashenc_delete_segment_file(s, os->segments[i]->file); @@ -1902,8 +1918,7 @@ static inline void dashenc_delete_media_segments(AVFormatContext *s, OutputStrea memmove(os->segments, os->segments + remove_count, os->nb_segments * sizeof(*os->segments)); } -static int dash_flush(AVFormatContext *s, int final, int stream) -{ +static int dash_flush(AVFormatContext *s, int final, int stream) { DASHContext *c = s->priv_data; int i, ret = 0; @@ -1982,8 +1997,10 @@ static int dash_flush(AVFormatContext *s, int final, int stream) if (!os->bit_rate && !os->first_segment_bit_rate) { os->first_segment_bit_rate = (int64_t) range_length * 8 * AV_TIME_BASE / duration; } - add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length, next_exp_index); - av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, os->full_path); + add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length, + next_exp_index); + av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, + os->full_path); os->pos += range_length; } @@ -2016,7 +2033,6 @@ static int dash_flush(AVFormatContext *s, int final, int stream) seg->start_pos += sidx_size; } } - } } } @@ -2036,18 +2052,17 @@ static int dash_flush(AVFormatContext *s, int final, int stream) return ret; } -static int dash_parse_prft(DASHContext *c, AVPacket *pkt) -{ +static int dash_parse_prft(DASHContext *c, AVPacket *pkt) { OutputStream *os = &c->streams[pkt->stream_index]; AVProducerReferenceTime *prft; size_t side_data_size; - prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &side_data_size); + prft = (AVProducerReferenceTime *) av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &side_data_size); if (!prft || side_data_size != sizeof(AVProducerReferenceTime) || (prft->flags && prft->flags != 24)) { // No encoder generated or user provided capture time AVProducerReferenceTime side data. Instead // of letting the mov muxer generate one, do it here so we can also use it for the manifest. - prft = (AVProducerReferenceTime *)av_packet_new_side_data(pkt, AV_PKT_DATA_PRFT, - sizeof(AVProducerReferenceTime)); + prft = (AVProducerReferenceTime *) av_packet_new_side_data(pkt, AV_PKT_DATA_PRFT, + sizeof(AVProducerReferenceTime)); if (!prft) return AVERROR(ENOMEM); prft->wallclock = av_gettime(); @@ -2062,8 +2077,7 @@ static int dash_parse_prft(DASHContext *c, AVPacket *pkt) return 0; } -static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) -{ +static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) { DASHContext *c = s->priv_data; AVStream *st = s->streams[pkt->stream_index]; OutputStream *os = &c->streams[pkt->stream_index]; @@ -2090,7 +2104,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) if (os->first_pts == AV_NOPTS_VALUE && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) { pkt->pts -= pkt->dts; - pkt->dts = 0; + pkt->dts = 0; } if (c->write_prft) { @@ -2121,16 +2135,16 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) int64_t frame_duration = 0; switch (os->frag_type) { - case FRAG_TYPE_DURATION: - frame_duration = os->frag_duration; - break; - case FRAG_TYPE_EVERY_FRAME: - frame_duration = av_rescale_q(pkt->duration, st->time_base, AV_TIME_BASE_Q); - break; + case FRAG_TYPE_DURATION: + frame_duration = os->frag_duration; + break; + case FRAG_TYPE_EVERY_FRAME: + frame_duration = av_rescale_q(pkt->duration, st->time_base, AV_TIME_BASE_Q); + break; } - os->availability_time_offset = ((double) os->seg_duration - - frame_duration) / AV_TIME_BASE; + os->availability_time_offset = ((double) os->seg_duration - + frame_duration) / AV_TIME_BASE; as->max_frag_duration = FFMAX(frame_duration, as->max_frag_duration); } @@ -2160,18 +2174,18 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) seg_end_duration, AV_TIME_BASE_Q) >= 0) { if (!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { c->last_duration = av_rescale_q(pkt->pts - os->start_pts, - st->time_base, - AV_TIME_BASE_Q); + st->time_base, + AV_TIME_BASE_Q); c->total_duration = av_rescale_q(pkt->pts - os->first_pts, - st->time_base, - AV_TIME_BASE_Q); + st->time_base, + AV_TIME_BASE_Q); if ((!c->use_timeline || !c->use_template) && os->last_duration) { - if (c->last_duration < os->last_duration*9/10 || - c->last_duration > os->last_duration*11/10) { + if (c->last_duration < os->last_duration * 9 / 10 || + c->last_duration > os->last_duration * 11 / 10) { av_log(s, AV_LOG_WARNING, - "Segment durations differ too much, enable use_timeline " - "and use_template, or keep a stricter keyframe interval\n"); + "Segment durations differ too much, enable use_timeline " + "and use_template, or keep a stricter keyframe interval\n"); } } } @@ -2215,13 +2229,14 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) int64_t frag_duration = av_rescale_q(os->total_pkt_duration, st->time_base, AV_TIME_BASE_Q); os->availability_time_offset = ((double) os->seg_duration - - frag_duration) / AV_TIME_BASE; - as->max_frag_duration = FFMAX(frag_duration, as->max_frag_duration); + frag_duration) / AV_TIME_BASE; + as->max_frag_duration = FFMAX(frag_duration, as->max_frag_duration); } } } - if (pkt->flags & AV_PKT_FLAG_KEY && (os->packets_written || os->nb_segments) && !os->gop_size && as->trick_idx < 0) { + if (pkt->flags & AV_PKT_FLAG_KEY && (os->packets_written || os->nb_segments) && !os->gop_size && as->trick_idx < + 0) { os->gop_size = os->last_duration + av_rescale_q(os->total_pkt_duration, st->time_base, AV_TIME_BASE_Q); c->max_gop_size = FFMAX(c->max_gop_size, os->gop_size); } @@ -2277,7 +2292,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) int len = 0; uint8_t *buf = NULL; avio_flush(os->ctx->pb); - len = avio_get_dyn_buf (os->ctx->pb, &buf); + len = avio_get_dyn_buf(os->ctx->pb, &buf); if (os->out) { avio_write(os->out, buf + os->written_len, len - os->written_len); avio_flush(os->out); @@ -2288,8 +2303,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) return ret; } -static int dash_write_trailer(AVFormatContext *s) -{ +static int dash_write_trailer(AVFormatContext *s) { DASHContext *c = s->priv_data; int i; @@ -2331,8 +2345,7 @@ static int dash_write_trailer(AVFormatContext *s) } static int dash_check_bitstream(AVFormatContext *s, AVStream *st, - const AVPacket *avpkt) -{ + const AVPacket *avpkt) { DASHContext *c = s->priv_data; OutputStream *os = &c->streams[st->index]; AVFormatContext *oc = os->ctx; @@ -2341,9 +2354,9 @@ static int dash_check_bitstream(AVFormatContext *s, AVStream *st, int ret; ret = ffofmt(oc->oformat)->check_bitstream(oc, ost, avpkt); if (ret == 1) { - FFStream *const sti = ffstream(st); + FFStream *const sti = ffstream(st); FFStream *const osti = ffstream(ost); - sti->bsfc = osti->bsfc; + sti->bsfc = osti->bsfc; osti->bsfc = NULL; } return ret; @@ -2354,74 +2367,204 @@ static int dash_check_bitstream(AVFormatContext *s, AVStream *st, #define OFFSET(x) offsetof(DASHContext, x) #define E AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "adaptation_sets", "Adaptation sets. Syntax: id=0,streams=0,1,2 id=1,streams=3,4 and so on", OFFSET(adaptation_sets), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, - { "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, .unit = "segment_type"}, - { "auto", "select segment file format based on codec", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_AUTO }, 0, UINT_MAX, E, .unit = "segment_type"}, - { "mp4", "make segment file in ISOBMFF format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_MP4 }, 0, UINT_MAX, E, .unit = "segment_type"}, - { "webm", "make segment file in WebM format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_WEBM }, 0, UINT_MAX, E, .unit = "segment_type"}, - { "extra_window_size", "number of segments kept outside of the manifest before removing from disk", OFFSET(extra_window_size), AV_OPT_TYPE_INT, { .i64 = 5 }, 0, INT_MAX, E }, - { "format_options","set list of options for the container format (mp4/webm) used for dash", OFFSET(format_options), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, E}, - { "frag_duration", "fragment duration (in seconds, fractional value can be set)", OFFSET(frag_duration), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT_MAX, E }, - { "frag_type", "set type of interval for fragments", OFFSET(frag_type), AV_OPT_TYPE_INT, {.i64 = FRAG_TYPE_NONE }, 0, FRAG_TYPE_NB - 1, E, .unit = "frag_type"}, - { "none", "one fragment per segment", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_NONE }, 0, UINT_MAX, E, .unit = "frag_type"}, - { "every_frame", "fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_EVERY_FRAME }, 0, UINT_MAX, E, .unit = "frag_type"}, - { "duration", "fragment at specific time intervals", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_DURATION }, 0, UINT_MAX, E, .unit = "frag_type"}, - { "pframes", "fragment at keyframes and following P-Frame reordering (Video only, experimental)", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_PFRAMES }, 0, UINT_MAX, E, .unit = "frag_type"}, - { "global_sidx", "Write global SIDX atom. Applicable only for single file, mp4 output, non-streaming mode", OFFSET(global_sidx), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, - { "hls_master_name", "HLS master playlist name", OFFSET(hls_master_name), AV_OPT_TYPE_STRING, {.str = "master.m3u8"}, 0, 0, E }, - { "hls_playlist", "Generate HLS playlist files(master.m3u8, media_%d.m3u8)", OFFSET(hls_playlist), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, - { "http_opts", "HTTP protocol options", OFFSET(http_opts), AV_OPT_TYPE_DICT, { .str = NULL }, 0, 0, E }, - { "http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, - { "http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, - { "ignore_io_errors", "Ignore IO errors during open and write. Useful for long-duration runs with network output", OFFSET(ignore_io_errors), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, - { "index_correction", "Enable/Disable segment index correction logic", OFFSET(index_correction), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, - { "init_seg_name", "DASH-templated name to used for the initialization segment", OFFSET(init_seg_name), AV_OPT_TYPE_STRING, {.str = "init-stream$RepresentationID$.$ext$"}, 0, 0, E }, - { "ldash", "Enable Low-latency dash. Constrains the value of a few elements", OFFSET(ldash), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, - { "lhls", "Enable Low-latency HLS(Experimental). Adds #EXT-X-PREFETCH tag with current segment's URI", OFFSET(lhls), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, - { "master_m3u8_publish_rate", "Publish master playlist every after this many segment intervals", OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT_MAX, E}, - { "max_playback_rate", "Set desired maximum playback rate", OFFSET(max_playback_rate), AV_OPT_TYPE_RATIONAL, { .dbl = 1.0 }, 0.5, 1.5, E }, - { "media_seg_name", "DASH-templated name to used for the media segments", OFFSET(media_seg_name), AV_OPT_TYPE_STRING, {.str = "chunk-stream$RepresentationID$-$Number%05d$.$ext$"}, 0, 0, E }, - { "method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, - { "min_playback_rate", "Set desired minimum playback rate", OFFSET(min_playback_rate), AV_OPT_TYPE_RATIONAL, { .dbl = 1.0 }, 0.5, 1.5, E }, - { "mpd_profile", "Set profiles. Elements and values used in the manifest may be constrained by them", OFFSET(profile), AV_OPT_TYPE_FLAGS, {.i64 = MPD_PROFILE_DASH }, 0, UINT_MAX, E, .unit = "mpd_profile"}, - { "dash", "MPEG-DASH ISO Base media file format live profile", 0, AV_OPT_TYPE_CONST, {.i64 = MPD_PROFILE_DASH }, 0, UINT_MAX, E, .unit = "mpd_profile"}, - { "dvb_dash", "DVB-DASH profile", 0, AV_OPT_TYPE_CONST, {.i64 = MPD_PROFILE_DVB }, 0, UINT_MAX, E, .unit = "mpd_profile"}, - { "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, - { "seg_duration", "segment duration (in seconds, fractional value can be set)", OFFSET(seg_duration), AV_OPT_TYPE_DURATION, { .i64 = 5000000 }, 0, INT_MAX, E }, - { "single_file", "Store all segments in one file, accessed using byte ranges", OFFSET(single_file), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, - { "single_file_name", "DASH-templated name to be used for baseURL. Implies storing all segments in one file, accessed using byte ranges", OFFSET(single_file_name), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, - { "streaming", "Enable/Disable streaming mode of output. Each frame will be moof fragment", OFFSET(streaming), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, - { "target_latency", "Set desired target latency for Low-latency dash", OFFSET(target_latency), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT_MAX, E }, - { "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E }, - { "update_period", "Set the mpd update interval", OFFSET(update_period), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, E}, - { "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E }, - { "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E }, - { "utc_timing_url", "URL of the page that will return the UTC timestamp in ISO format", OFFSET(utc_timing_url), AV_OPT_TYPE_STRING, { 0 }, 0, 0, E }, - { "window_size", "number of segments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E }, - { "write_prft", "Write producer reference time element", OFFSET(write_prft), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, E}, - { NULL }, + { + "adaptation_sets", "Adaptation sets. Syntax: id=0,streams=0,1,2 id=1,streams=3,4 and so on", + OFFSET(adaptation_sets), AV_OPT_TYPE_STRING, {0}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM + }, + { + "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, .unit = "segment_type" + }, + { + "auto", "select segment file format based on codec", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_AUTO}, 0, + UINT_MAX, E, .unit = "segment_type" + }, + { + "mp4", "make segment file in ISOBMFF format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_MP4}, 0, UINT_MAX, E, + .unit = "segment_type" + }, + { + "webm", "make segment file in WebM format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_WEBM}, 0, UINT_MAX, E, + .unit = "segment_type" + }, + { + "extra_window_size", "number of segments kept outside of the manifest before removing from disk", + OFFSET(extra_window_size), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E + }, + { + "format_options", "set list of options for the container format (mp4/webm) used for dash", + OFFSET(format_options), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, E + }, + { + "frag_duration", "fragment duration (in seconds, fractional value can be set)", OFFSET(frag_duration), + AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, INT_MAX, E + }, + { + "frag_type", "set type of interval for fragments", OFFSET(frag_type), AV_OPT_TYPE_INT, {.i64 = FRAG_TYPE_NONE}, + 0, FRAG_TYPE_NB - 1, E, .unit = "frag_type" + }, + { + "none", "one fragment per segment", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_NONE}, 0, UINT_MAX, E, + .unit = "frag_type" + }, + { + "every_frame", "fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_EVERY_FRAME}, 0, UINT_MAX, E, + .unit = "frag_type" + }, + { + "duration", "fragment at specific time intervals", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_DURATION}, 0, + UINT_MAX, E, .unit = "frag_type" + }, + { + "pframes", "fragment at keyframes and following P-Frame reordering (Video only, experimental)", 0, + AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_PFRAMES}, 0, UINT_MAX, E, .unit = "frag_type" + }, + { + "global_sidx", "Write global SIDX atom. Applicable only for single file, mp4 output, non-streaming mode", + OFFSET(global_sidx), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E + }, + { + "hls_master_name", "HLS master playlist name", OFFSET(hls_master_name), AV_OPT_TYPE_STRING, + {.str = "master.m3u8"}, 0, 0, E + }, + { + "hls_playlist", "Generate HLS playlist files(master.m3u8, media_%d.m3u8)", OFFSET(hls_playlist), + AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E + }, + {"http_opts", "HTTP protocol options", OFFSET(http_opts), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, E}, + { + "http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, + 1, E + }, + { + "http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent), AV_OPT_TYPE_STRING, + {.str = NULL}, 0, 0, E + }, + { + "ignore_io_errors", "Ignore IO errors during open and write. Useful for long-duration runs with network output", + OFFSET(ignore_io_errors), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E + }, + { + "index_correction", "Enable/Disable segment index correction logic", OFFSET(index_correction), AV_OPT_TYPE_BOOL, + {.i64 = 0}, 0, 1, E + }, + { + "init_seg_name", "DASH-templated name to used for the initialization segment", OFFSET(init_seg_name), + AV_OPT_TYPE_STRING, {.str = "init-stream$RepresentationID$.$ext$"}, 0, 0, E + }, + { + "ldash", "Enable Low-latency dash. Constrains the value of a few elements", OFFSET(ldash), AV_OPT_TYPE_BOOL, + {.i64 = 0}, 0, 1, E + }, + { + "lhls", "Enable Low-latency HLS(Experimental). Adds #EXT-X-PREFETCH tag with current segment's URI", + OFFSET(lhls), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E + }, + { + "master_m3u8_publish_rate", "Publish master playlist every after this many segment intervals", + OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT_MAX, E + }, + { + "max_playback_rate", "Set desired maximum playback rate", OFFSET(max_playback_rate), AV_OPT_TYPE_RATIONAL, + {.dbl = 1.0}, 0.5, 1.5, E + }, + { + "media_seg_name", "DASH-templated name to used for the media segments", OFFSET(media_seg_name), + AV_OPT_TYPE_STRING, {.str = "chunk-stream$RepresentationID$-$Number%05d$.$ext$"}, 0, 0, E + }, + {"method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + { + "min_playback_rate", "Set desired minimum playback rate", OFFSET(min_playback_rate), AV_OPT_TYPE_RATIONAL, + {.dbl = 1.0}, 0.5, 1.5, E + }, + { + "mpd_profile", "Set profiles. Elements and values used in the manifest may be constrained by them", + OFFSET(profile), AV_OPT_TYPE_FLAGS, {.i64 = MPD_PROFILE_DASH}, 0, UINT_MAX, E, .unit = "mpd_profile" + }, + { + "dash", "MPEG-DASH ISO Base media file format live profile", 0, AV_OPT_TYPE_CONST, {.i64 = MPD_PROFILE_DASH}, 0, + UINT_MAX, E, .unit = "mpd_profile" + }, + { + "dvb_dash", "DVB-DASH profile", 0, AV_OPT_TYPE_CONST, {.i64 = MPD_PROFILE_DVB}, 0, UINT_MAX, E, + .unit = "mpd_profile" + }, + { + "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, + 1, E + }, + { + "seg_duration", "segment duration (in seconds, fractional value can be set)", OFFSET(seg_duration), + AV_OPT_TYPE_DURATION, {.i64 = 5000000}, 0, INT_MAX, E + }, + { + "single_file", "Store all segments in one file, accessed using byte ranges", OFFSET(single_file), + AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E + }, + { + "single_file_name", + "DASH-templated name to be used for baseURL. Implies storing all segments in one file, accessed using byte ranges", + OFFSET(single_file_name), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E + }, + { + "streaming", "Enable/Disable streaming mode of output. Each frame will be moof fragment", OFFSET(streaming), + AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E + }, + { + "target_latency", "Set desired target latency for Low-latency dash", OFFSET(target_latency), + AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, INT_MAX, E + }, + { + "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, + INT_MAX, .flags = E + }, + { + "update_period", "Set the mpd update interval", OFFSET(update_period), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, + INT64_MAX, E + }, + { + "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_BOOL, + {.i64 = 1}, 0, 1, E + }, + { + "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, + 1, E + }, + { + "utc_timing_url", "URL of the page that will return the UTC timestamp in ISO format", OFFSET(utc_timing_url), + AV_OPT_TYPE_STRING, {0}, 0, 0, E + }, + { + "window_size", "number of segments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, + INT_MAX, E + }, + { + "write_prft", "Write producer reference time element", OFFSET(write_prft), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, + E + }, + {NULL}, }; static const AVClass dash_class = { .class_name = "dash muxer", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, }; const FFOutputFormat ff_dash_muxer = { - .p.name = "dash", - .p.long_name = NULL_IF_CONFIG_SMALL("DASH Muxer"), - .p.extensions = "mpd", - .p.audio_codec = AV_CODEC_ID_AAC, - .p.video_codec = AV_CODEC_ID_H264, - .p.flags = AVFMT_GLOBALHEADER | AVFMT_NOFILE | AVFMT_TS_NEGATIVE, - .p.priv_class = &dash_class, + .p.name = "dash", + .p.long_name = NULL_IF_CONFIG_SMALL("DASH Muxer"), + .p.extensions = "mpd", + .p.audio_codec = AV_CODEC_ID_AAC, + .p.video_codec = AV_CODEC_ID_H264, + .p.flags = AVFMT_GLOBALHEADER | AVFMT_NOFILE | AVFMT_TS_NEGATIVE, + .p.priv_class = &dash_class, .priv_data_size = sizeof(DASHContext), - .init = dash_init, - .write_header = dash_write_header, - .write_packet = dash_write_packet, - .write_trailer = dash_write_trailer, - .deinit = dash_free, + .init = dash_init, + .write_header = dash_write_header, + .write_packet = dash_write_packet, + .write_trailer = dash_write_trailer, + .deinit = dash_free, .check_bitstream = dash_check_bitstream, }; -- 2.49.1 >>From ac11dd508c3e06ec4b59e38098b6f24ef16b0be3 Mon Sep 17 00:00:00 2001 From: Damitha Gunawardena Date: Wed, 24 Sep 2025 20:28:30 +1000 Subject: [PATCH 2/2] preserve metadata in dashenc --- libavformat/dashenc.c | 619 ++++++++++++++++-------------------------- 1 file changed, 239 insertions(+), 380 deletions(-) diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index 7ca46e201a..9a5a2bc675 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -123,10 +123,10 @@ typedef struct OutputStream { int last_flags; int bit_rate; int first_segment_bit_rate; - SegmentType segment_type; /* segment type selected for this particular stream */ + SegmentType segment_type; /* segment type selected for this particular stream */ const char *format_name; const char *extension_name; - const char *single_file_name; /* file names selected for this particular stream */ + const char *single_file_name; /* file names selected for this particular stream */ const char *init_seg_name; const char *media_seg_name; @@ -148,7 +148,7 @@ typedef struct OutputStream { } OutputStream; typedef struct DASHContext { - const AVClass *class; /* Class for private options. */ + const AVClass *class; /* Class for private options. */ char *adaptation_sets; AdaptationSet *as; int nb_as; @@ -168,7 +168,7 @@ typedef struct DASHContext { time_t start_time_s; int64_t presentation_time_offset; char dirname[1024]; - const char *single_file_name; /* file names as specified in options */ + const char *single_file_name; /* file names as specified in options */ const char *init_seg_name; const char *media_seg_name; const char *utc_timing_url; @@ -187,7 +187,7 @@ typedef struct DASHContext { int index_correction; AVDictionary *format_options; int global_sidx; - SegmentType segment_type_option; /* segment type as specified in options */ + SegmentType segment_type_option; /* segment type as specified in options */ int ignore_io_errors; int lhls; int ldash; @@ -210,12 +210,12 @@ static const struct codec_string { enum AVCodecID id; const char str[8]; } codecs[] = { - {AV_CODEC_ID_VP8, "vp8"}, - {AV_CODEC_ID_VP9, "vp9"}, - {AV_CODEC_ID_VORBIS, "vorbis"}, - {AV_CODEC_ID_OPUS, "opus"}, - {AV_CODEC_ID_FLAC, "flac"}, - {AV_CODEC_ID_NONE} + { AV_CODEC_ID_VP8, "vp8" }, + { AV_CODEC_ID_VP9, "vp9" }, + { AV_CODEC_ID_VORBIS, "vorbis" }, + { AV_CODEC_ID_OPUS, "opus" }, + { AV_CODEC_ID_FLAC, "flac" }, + { AV_CODEC_ID_NONE } }; static int dashenc_io_open(AVFormatContext *s, AVIOContext **pb, char *filename, @@ -256,19 +256,22 @@ static void dashenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filenam } } -static const char *get_format_str(SegmentType segment_type) { +static const char *get_format_str(SegmentType segment_type) +{ switch (segment_type) { - case SEGMENT_TYPE_MP4: return "mp4"; - case SEGMENT_TYPE_WEBM: return "webm"; + case SEGMENT_TYPE_MP4: return "mp4"; + case SEGMENT_TYPE_WEBM: return "webm"; } return NULL; } -static const char *get_extension_str(SegmentType type, int single_file) { +static const char *get_extension_str(SegmentType type, int single_file) +{ switch (type) { - case SEGMENT_TYPE_MP4: return single_file ? "mp4" : "m4s"; - case SEGMENT_TYPE_WEBM: return "webm"; - default: return NULL; + + case SEGMENT_TYPE_MP4: return single_file ? "mp4" : "m4s"; + case SEGMENT_TYPE_WEBM: return "webm"; + default: return NULL; } } @@ -279,7 +282,8 @@ static int handle_io_open_error(AVFormatContext *s, int err, char *url) { return c->ignore_io_errors ? 0 : err; } -static inline SegmentType select_segment_type(SegmentType segment_type, enum AVCodecID codec_id) { +static inline SegmentType select_segment_type(SegmentType segment_type, enum 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) { @@ -292,7 +296,8 @@ static inline SegmentType select_segment_type(SegmentType segment_type, enum AVC return segment_type; } -static int init_segment_types(AVFormatContext *s) { +static int init_segment_types(AVFormatContext *s) +{ DASHContext *c = s->priv_data; int has_mp4_streams = 0; for (int i = 0; i < s->nb_streams; ++i) { @@ -315,8 +320,8 @@ static int init_segment_types(AVFormatContext *s) { } if (c->hls_playlist && !has_mp4_streams) { - av_log(s, AV_LOG_WARNING, "No mp4 streams, disabling HLS manifest generation\n"); - c->hls_playlist = 0; + av_log(s, AV_LOG_WARNING, "No mp4 streams, disabling HLS manifest generation\n"); + c->hls_playlist = 0; } return 0; @@ -338,8 +343,9 @@ static void set_vp9_codec_str(AVFormatContext *s, AVCodecParameters *par, } static void set_codec_str(AVFormatContext *s, AVCodecParameters *par, - AVRational *frame_rate, char *str, int size) { - const AVCodecTag *tags[2] = {NULL, NULL}; + AVRational *frame_rate, char *str, int size) +{ + const AVCodecTag *tags[2] = { NULL, NULL }; uint32_t tag; int i; @@ -432,7 +438,8 @@ static void set_codec_str(AVFormatContext *s, AVCodecParameters *par, } } -static int flush_dynbuf(DASHContext *c, OutputStream *os, int *range_length) { +static int flush_dynbuf(DASHContext *c, OutputStream *os, int *range_length) +{ uint8_t *buffer; if (!os->ctx->pb) { @@ -460,7 +467,8 @@ static int flush_dynbuf(DASHContext *c, OutputStream *os, int *range_length) { } } -static void set_http_options(AVDictionary **options, DASHContext *c) { +static void set_http_options(AVDictionary **options, DASHContext *c) +{ if (c->method) av_dict_set(options, "method", c->method, 0); av_dict_copy(options, c->http_opts, 0); @@ -485,7 +493,7 @@ static void get_start_index_number(OutputStream *os, DASHContext *c, *start_index = 0; *start_number = 1; if (c->window_size) { - *start_index = FFMAX(os->nb_segments - c->window_size, 0); + *start_index = FFMAX(os->nb_segments - c->window_size, 0); *start_number = FFMAX(os->segment_index - c->window_size, 1); } } @@ -548,10 +556,10 @@ static void write_hls_media_playlist(OutputStream *os, AVFormatContext *s, seg->prog_date_time = prog_date_time; ret = ff_hls_write_file_entry(c->m3u8_out, 0, c->single_file, - (double) seg->duration / timescale, 0, - seg->range_length, seg->start_pos, NULL, - c->single_file ? os->initfile : seg->file, - &prog_date_time, 0, 0, 0); + (double) seg->duration / timescale, 0, + seg->range_length, seg->start_pos, NULL, + c->single_file ? os->initfile : seg->file, + &prog_date_time, 0, 0, 0); if (ret < 0) { av_log(os->ctx, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); } @@ -569,7 +577,8 @@ static void write_hls_media_playlist(OutputStream *os, AVFormatContext *s, ff_rename(temp_filename_hls, filename_hls, os->ctx); } -static int flush_init_segment(AVFormatContext *s, OutputStream *os) { +static int flush_init_segment(AVFormatContext *s, OutputStream *os) +{ DASHContext *c = s->priv_data; int ret, range_length; @@ -586,7 +595,8 @@ static int flush_init_segment(AVFormatContext *s, OutputStream *os) { return 0; } -static void dash_free(AVFormatContext *s) { +static void dash_free(AVFormatContext *s) +{ DASHContext *c = s->priv_data; int i, j; @@ -628,7 +638,8 @@ static void dash_free(AVFormatContext *s) { } static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatContext *s, - int representation_id, int final) { + int representation_id, int final) +{ DASHContext *c = s->priv_data; int i, start_index, start_number; get_start_index_number(os, c, &start_index, &start_number); @@ -645,15 +656,14 @@ static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatCont if (c->streaming && os->availability_time_offset && !final) avio_printf(out, "availabilityTimeComplete=\"false\" "); - avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\"", os->init_seg_name, os->media_seg_name, - c->use_timeline ? start_number : 1); + avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\"", os->init_seg_name, os->media_seg_name, c->use_timeline ? start_number : 1); if (c->presentation_time_offset) avio_printf(out, " presentationTimeOffset=\"%"PRId64"\"", c->presentation_time_offset); avio_printf(out, ">\n"); if (c->use_timeline) { int64_t cur_time = 0; avio_printf(out, "\t\t\t\t\t\n"); - for (i = start_index; i < os->nb_segments;) { + for (i = start_index; i < os->nb_segments; ) { Segment *seg = os->segments[i]; int repeat = 0; avio_printf(out, "\t\t\t\t\t\tduration); while (i + repeat + 1 < os->nb_segments && os->segments[i + repeat + 1]->duration == seg->duration && - os->segments[i + repeat + 1]->time == os->segments[i + repeat]->time + os->segments[i + repeat]-> - duration) + os->segments[i + repeat + 1]->time == os->segments[i + repeat]->time + os->segments[i + repeat]->duration) repeat++; if (repeat > 0) avio_printf(out, "r=\"%d\" ", repeat); @@ -678,23 +687,18 @@ static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatCont avio_printf(out, "\t\t\t\t\n"); } else if (c->single_file) { avio_printf(out, "\t\t\t\t%s\n", os->initfile); - avio_printf(out, "\t\t\t\t\n", - AV_TIME_BASE, FFMIN(os->seg_duration, os->last_duration), start_number); - avio_printf(out, "\t\t\t\t\t\n", os->init_start_pos, - os->init_start_pos + os->init_range_length - 1); + avio_printf(out, "\t\t\t\t\n", AV_TIME_BASE, FFMIN(os->seg_duration, os->last_duration), start_number); + avio_printf(out, "\t\t\t\t\t\n", os->init_start_pos, os->init_start_pos + os->init_range_length - 1); for (i = start_index; i < os->nb_segments; i++) { Segment *seg = os->segments[i]; - avio_printf(out, "\t\t\t\t\tstart_pos, - seg->start_pos + seg->range_length - 1); + avio_printf(out, "\t\t\t\t\tstart_pos, seg->start_pos + seg->range_length - 1); if (seg->index_length) - avio_printf(out, "indexRange=\"%"PRId64"-%"PRId64"\" ", seg->start_pos, - seg->start_pos + seg->index_length - 1); + avio_printf(out, "indexRange=\"%"PRId64"-%"PRId64"\" ", seg->start_pos, seg->start_pos + seg->index_length - 1); avio_printf(out, "/>\n"); } avio_printf(out, "\t\t\t\t\n"); } else { - avio_printf(out, "\t\t\t\t\n", - AV_TIME_BASE, FFMIN(os->seg_duration, os->last_duration), start_number); + avio_printf(out, "\t\t\t\t\n", AV_TIME_BASE, FFMIN(os->seg_duration, os->last_duration), start_number); avio_printf(out, "\t\t\t\t\t\n", os->initfile); for (i = start_index; i < os->nb_segments; i++) { Segment *seg = os->segments[i]; @@ -705,10 +709,11 @@ static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatCont if (!c->lhls || final) { write_hls_media_playlist(os, s, representation_id, final, NULL); } + } static char *xmlescape(const char *str) { - int outlen = strlen(str) * 3 / 2 + 6; + int outlen = strlen(str)*3/2 + 6; char *out = av_realloc(NULL, outlen + 1); int pos = 0; if (!out) @@ -747,7 +752,8 @@ static char *xmlescape(const char *str) { return out; } -static void write_time(AVIOContext *out, int64_t time) { +static void write_time(AVIOContext *out, int64_t time) +{ int seconds = time / AV_TIME_BASE; int fractions = time % AV_TIME_BASE; int minutes = seconds / 60; @@ -762,7 +768,8 @@ static void write_time(AVIOContext *out, int64_t time) { avio_printf(out, "%d.%dS", seconds, fractions / (AV_TIME_BASE / 10)); } -static void format_date(char *buf, int size, int64_t time_us) { +static void format_date(char *buf, int size, int64_t time_us) +{ struct tm *ptm, tmbuf; int64_t time_ms = time_us / 1000; const time_t time_s = time_ms / 1000; @@ -780,21 +787,18 @@ static void format_date(char *buf, int size, int64_t time_us) { } static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_index, - int final) { + int final) +{ DASHContext *c = s->priv_data; AdaptationSet *as = &c->as[as_index]; AVDictionaryEntry *lang, *role; int i; - avio_printf( - out, - "\t\tid, as->media_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio"); - if (as->media_type == AVMEDIA_TYPE_VIDEO && as->max_frame_rate.num && !as->ambiguous_frame_rate && av_cmp_q( - as->min_frame_rate, as->max_frame_rate) < 0) + avio_printf(out, "\t\tid, as->media_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio"); + if (as->media_type == AVMEDIA_TYPE_VIDEO && as->max_frame_rate.num && !as->ambiguous_frame_rate && av_cmp_q(as->min_frame_rate, as->max_frame_rate) < 0) avio_printf(out, " maxFrameRate=\"%d/%d\"", as->max_frame_rate.num, as->max_frame_rate.den); - else if (as->media_type == AVMEDIA_TYPE_VIDEO && as->max_frame_rate.num && !as->ambiguous_frame_rate && !av_cmp_q( - as->min_frame_rate, as->max_frame_rate)) + else if (as->media_type == AVMEDIA_TYPE_VIDEO && as->max_frame_rate.num && !as->ambiguous_frame_rate && !av_cmp_q(as->min_frame_rate, as->max_frame_rate)) avio_printf(out, " frameRate=\"%d/%d\"", as->max_frame_rate.num, as->max_frame_rate.den); if (as->media_type == AVMEDIA_TYPE_VIDEO) { avio_printf(out, " maxWidth=\"%d\" maxHeight=\"%d\"", as->max_width, as->max_height); @@ -808,10 +812,7 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind if (!final && c->ldash && as->max_frag_duration && !(c->profile & MPD_PROFILE_DVB)) avio_printf(out, "\t\t\t\n", as->max_frag_duration); if (as->trick_idx >= 0) - avio_printf( - out, - "\t\t\t\n", - as->id, as->trick_idx); + avio_printf(out, "\t\t\t\n", as->id, as->trick_idx); role = av_dict_get(as->metadata, "role", NULL, 0); if (role) avio_printf(out, "\t\t\t\n", role->value); @@ -834,10 +835,8 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"", os->first_segment_bit_rate); if (as->media_type == AVMEDIA_TYPE_VIDEO) { - avio_printf( - out, "\t\t\tformat_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, - s->streams[i]->codecpar->height); + avio_printf(out, "\t\t\tformat_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height); if (st->codecpar->field_order == AV_FIELD_UNKNOWN) avio_printf(out, " scanType=\"unknown\""); else if (st->codecpar->field_order != AV_FIELD_PROGRESSIVE) @@ -848,31 +847,21 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind if (as->trick_idx >= 0) { AdaptationSet *tas = &c->as[as->trick_idx]; if (!as->ambiguous_frame_rate && !tas->ambiguous_frame_rate) - avio_printf(out, " maxPlayoutRate=\"%d\"", - FFMAX((int)av_q2d(av_div_q(tas->min_frame_rate, as->min_frame_rate)), 1)); + avio_printf(out, " maxPlayoutRate=\"%d\"", FFMAX((int)av_q2d(av_div_q(tas->min_frame_rate, as->min_frame_rate)), 1)); } if (!os->coding_dependency) avio_printf(out, " codingDependency=\"false\""); avio_printf(out, ">\n"); } else { - avio_printf( - out, - "\t\t\t\n", + avio_printf(out, "\t\t\t\n", i, os->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->sample_rate); - avio_printf( - out, - "\t\t\t\t\n", + avio_printf(out, "\t\t\t\t\n", s->streams[i]->codecpar->ch_layout.nb_channels); } if (!final && c->write_prft && os->producer_reference_time_str[0]) { - avio_printf( - out, - "\t\t\t\t\n", - i, os->producer_reference_time.flags ? "captured" : "encoder", os->producer_reference_time_str, - c->presentation_time_offset); - avio_printf(out, "\t\t\t\t\t\n", - c->utc_timing_url); + avio_printf(out, "\t\t\t\t\n", + i, os->producer_reference_time.flags ? "captured" : "encoder", os->producer_reference_time_str, c->presentation_time_offset); + avio_printf(out, "\t\t\t\t\t\n", c->utc_timing_url); avio_printf(out, "\t\t\t\t\n"); } if (!final && c->ldash && os->gop_size && os->frag_type != FRAG_TYPE_NONE && !(c->profile & MPD_PROFILE_DVB) && @@ -886,7 +875,8 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind return 0; } -static int add_adaptation_set(AVFormatContext *s, AdaptationSet **as, enum AVMediaType type) { +static int add_adaptation_set(AVFormatContext *s, AdaptationSet **as, enum AVMediaType type) +{ DASHContext *c = s->priv_data; void *mem; @@ -909,7 +899,8 @@ static int add_adaptation_set(AVFormatContext *s, AdaptationSet **as, enum AVMed return 0; } -static int adaptation_set_add_stream(AVFormatContext *s, int as_idx, int i) { +static int adaptation_set_add_stream(AVFormatContext *s, int as_idx, int i) +{ DASHContext *c = s->priv_data; AdaptationSet *as = &c->as[as_idx - 1]; OutputStream *os = &c->streams[i]; @@ -931,7 +922,8 @@ static int adaptation_set_add_stream(AVFormatContext *s, int as_idx, int i) { return 0; } -static int parse_adaptation_sets(AVFormatContext *s) { +static int parse_adaptation_sets(AVFormatContext *s) +{ DASHContext *c = s->priv_data; const char *p = c->adaptation_sets; enum { new_set, parse_default, parsing_streams, parse_seg_duration, parse_frag_duration } state; @@ -1057,8 +1049,7 @@ static int parse_adaptation_sets(AVFormatContext *s) { if (*p) p++; state = parse_default; - } else if ((state != new_set) && av_strstart(p, "streams=", &p)) { - //descriptor and durations are optional + } else if ((state != new_set) && av_strstart(p, "streams=", &p)) { //descriptor and durations are optional state = parsing_streams; } else if (state == parsing_streams) { AdaptationSet *as = &c->as[c->nb_as - 1]; @@ -1082,8 +1073,7 @@ static int parse_adaptation_sets(AVFormatContext *s) { if ((ret = adaptation_set_add_stream(s, c->nb_as, i)) < 0) return ret; } - } else { - // select single stream + } else { // select single stream i = strtol(idx_str, &end_str, 10); if (idx_str == end_str || i < 0 || i >= s->nb_streams) { av_log(s, AV_LOG_ERROR, "Selected stream \"%s\" not found!\n", idx_str); @@ -1128,9 +1118,7 @@ end: break; } if (n >= c->nb_as) { - av_log(s, AV_LOG_ERROR, - "reference AdaptationSet id \"%d\" not found for trick mode AdaptationSet id \"%d\"\n", - as->trick_idx, as->id); + av_log(s, AV_LOG_ERROR, "reference AdaptationSet id \"%d\" not found for trick mode AdaptationSet id \"%d\"\n", as->trick_idx, as->id); return AVERROR(EINVAL); } } @@ -1138,7 +1126,8 @@ end: return 0; } -static int write_manifest(AVFormatContext *s, int final) { +static int write_manifest(AVFormatContext *s, int final) +{ DASHContext *c = s->priv_data; AVIOContext *out; char temp_filename[1024]; @@ -1150,8 +1139,7 @@ static int write_manifest(AVFormatContext *s, int final) { AVDictionary *opts = NULL; if (!use_rename && !warned_non_file++) - av_log(s, AV_LOG_ERROR, - "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n"); + av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n"); snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->url); set_http_options(&opts, c); @@ -1168,9 +1156,9 @@ static int write_manifest(AVFormatContext *s, int final) { "\txsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd\"\n" "\tprofiles=\""); if (c->profile & MPD_PROFILE_DASH) - avio_printf(out, "%s%s", "urn:mpeg:dash:profile:isoff-live:2011", c->profile & MPD_PROFILE_DVB ? "," : "\"\n"); + avio_printf(out, "%s%s", "urn:mpeg:dash:profile:isoff-live:2011", c->profile & MPD_PROFILE_DVB ? "," : "\"\n"); if (c->profile & MPD_PROFILE_DVB) - avio_printf(out, "%s", "urn:dvb:dash:profile:dvb-dash:2014\"\n"); + avio_printf(out, "%s", "urn:dvb:dash:profile:dvb-dash:2014\"\n"); avio_printf(out, "\ttype=\"%s\"\n", final ? "static" : "dynamic"); if (final) { @@ -1219,8 +1207,8 @@ static int write_manifest(AVFormatContext *s, int final) { avio_printf(out, " referenceId=\"%d\"", c->target_latency_refid); avio_printf(out, "/>\n"); } - if (av_cmp_q(c->min_playback_rate, (AVRational){1, 1}) || - av_cmp_q(c->max_playback_rate, (AVRational){1, 1})) + if (av_cmp_q(c->min_playback_rate, (AVRational) {1, 1}) || + av_cmp_q(c->max_playback_rate, (AVRational) {1, 1})) avio_printf(out, "\t\t\n", av_q2d(c->min_playback_rate), av_q2d(c->max_playback_rate)); avio_printf(out, "\t\n"); @@ -1243,8 +1231,7 @@ static int write_manifest(AVFormatContext *s, int final) { avio_printf(out, "\t\n"); if (c->utc_timing_url) - avio_printf(out, "\t\n", - c->utc_timing_url); + avio_printf(out, "\t\n", c->utc_timing_url); avio_printf(out, "\n"); avio_flush(out); @@ -1260,7 +1247,7 @@ static int write_manifest(AVFormatContext *s, int final) { // Publish master playlist only the configured rate if (c->master_playlist_created && (!c->master_publish_rate || - c->streams[0].segment_index % c->master_publish_rate)) + c->streams[0].segment_index % c->master_publish_rate)) return 0; if (*c->dirname) @@ -1337,6 +1324,7 @@ static int write_manifest(AVFormatContext *s, int final) { playlist_file, agroup, codec_str, NULL, NULL); } + } else { // treat audio streams as separate renditions @@ -1374,14 +1362,16 @@ static int write_manifest(AVFormatContext *s, int final) { return 0; } -static int dict_copy_entry(AVDictionary **dst, const AVDictionary *src, const char *key) { +static int dict_copy_entry(AVDictionary **dst, const AVDictionary *src, const char *key) +{ AVDictionaryEntry *entry = av_dict_get(src, key, NULL, 0); if (entry) av_dict_set(dst, key, entry->value, AV_DICT_DONT_OVERWRITE); return 0; } -static int dash_init(AVFormatContext *s) { +static int dash_init(AVFormatContext *s) +{ DASHContext *c = s->priv_data; int ret = 0, i; char *ptr; @@ -1444,31 +1434,27 @@ static int dash_init(AVFormatContext *s) { } if (c->write_prft && !c->utc_timing_url) { - av_log(s, AV_LOG_WARNING, - "Producer Reference Time element option will be ignored as utc_timing_url is not set\n"); + av_log(s, AV_LOG_WARNING, "Producer Reference Time element option will be ignored as utc_timing_url is not set\n"); c->write_prft = 0; } if (c->write_prft && !c->streaming) { - av_log(s, AV_LOG_WARNING, - "Producer Reference Time element option will be ignored as streaming is not enabled\n"); + av_log(s, AV_LOG_WARNING, "Producer Reference Time element option will be ignored as streaming is not enabled\n"); c->write_prft = 0; } if (c->ldash && !c->write_prft) { - av_log(s, AV_LOG_WARNING, - "Low Latency mode enabled without Producer Reference Time element option! Resulting manifest may not be complaint\n"); + av_log(s, AV_LOG_WARNING, "Low Latency mode enabled without Producer Reference Time element option! Resulting manifest may not be complaint\n"); } if (c->target_latency && !c->write_prft) { - av_log(s, AV_LOG_WARNING, - "Target latency option will be ignored as Producer Reference Time element will not be written\n"); + av_log(s, AV_LOG_WARNING, "Target latency option will be ignored as Producer Reference Time element will not be written\n"); c->target_latency = 0; } if (av_cmp_q(c->max_playback_rate, c->min_playback_rate) < 0) { av_log(s, AV_LOG_WARNING, "Minimum playback rate value is higher than the Maximum. Both will be ignored\n"); - c->min_playback_rate = c->max_playback_rate = (AVRational){1, 1}; + c->min_playback_rate = c->max_playback_rate = (AVRational) {1, 1}; } av_strlcpy(c->dirname, s->url, sizeof(c->dirname)); @@ -1505,7 +1491,8 @@ static int dash_init(AVFormatContext *s) { os->bit_rate = s->streams[i]->codecpar->bit_rate; if (!os->bit_rate) { - int level = s->strict_std_compliance >= FF_COMPLIANCE_STRICT ? AV_LOG_ERROR : AV_LOG_WARNING; + int level = s->strict_std_compliance >= FF_COMPLIANCE_STRICT ? + AV_LOG_ERROR : AV_LOG_WARNING; av_log(s, level, "No bit rate set for stream %d\n", i); if (s->strict_std_compliance >= FF_COMPLIANCE_STRICT) return AVERROR(EINVAL); @@ -1532,9 +1519,9 @@ static int dash_init(AVFormatContext *s) { } if (os->segment_type == SEGMENT_TYPE_WEBM) { - if ((!c->single_file && !av_match_ext(os->init_seg_name, os->format_name)) || + if ((!c->single_file && !av_match_ext(os->init_seg_name, os->format_name)) || (!c->single_file && !av_match_ext(os->media_seg_name, os->format_name)) || - (c->single_file && !av_match_ext(os->single_file_name, os->format_name))) { + ( c->single_file && !av_match_ext(os->single_file_name, os->format_name))) { 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 " @@ -1542,8 +1529,7 @@ static int dash_init(AVFormatContext *s) { } if (c->streaming) { // Streaming not supported as matroskaenc buffers internally before writing the output - av_log(s, AV_LOG_WARNING, - "One or more streams in WebM output format. Streaming option will be ignored\n"); + av_log(s, AV_LOG_WARNING, "One or more streams in WebM output format. Streaming option will be ignored\n"); c->streaming = 0; } } @@ -1555,10 +1541,10 @@ static int dash_init(AVFormatContext *s) { ctx->oformat = av_guess_format(os->format_name, NULL, NULL); if (!ctx->oformat) return AVERROR_MUXER_NOT_FOUND; - ctx->interrupt_callback = s->interrupt_callback; - ctx->opaque = s->opaque; - ctx->io_close2 = s->io_close2; - ctx->io_open = s->io_open; + ctx->interrupt_callback = s->interrupt_callback; + ctx->opaque = s->opaque; + ctx->io_close2 = s->io_close2; + ctx->io_open = s->io_open; ctx->strict_std_compliance = s->strict_std_compliance; if (!(st = avformat_new_stream(ctx, NULL))) @@ -1584,8 +1570,7 @@ static int dash_init(AVFormatContext *s) { if (c->single_file) { if (os->single_file_name) - ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), os->single_file_name, i, 0, os->bit_rate, - 0); + ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), os->single_file_name, i, 0, os->bit_rate, 0); else snprintf(os->initfile, sizeof(os->initfile), "%s-stream%d.%s", basename, i, os->format_name); } else { @@ -1620,8 +1605,7 @@ static int dash_init(AVFormatContext *s) { c->max_segment_duration = FFMAX(c->max_segment_duration, as->seg_duration); if (c->profile & MPD_PROFILE_DVB && (os->seg_duration > 15000000 || os->seg_duration < 960000)) { - av_log(s, AV_LOG_ERROR, "Segment duration %"PRId64" is outside the allowed range for DVB-DASH profile\n", - os->seg_duration); + av_log(s, AV_LOG_ERROR, "Segment duration %"PRId64" is outside the allowed range for DVB-DASH profile\n", os->seg_duration); return AVERROR(EINVAL); } @@ -1630,14 +1614,12 @@ static int dash_init(AVFormatContext *s) { os->frag_type = c->streaming ? FRAG_TYPE_EVERY_FRAME : FRAG_TYPE_NONE; } if (os->frag_type == FRAG_TYPE_DURATION && os->frag_duration > os->seg_duration) { - av_log(s, AV_LOG_ERROR, "Fragment duration %"PRId64" is longer than Segment duration %"PRId64"\n", - os->frag_duration, os->seg_duration); + av_log(s, AV_LOG_ERROR, "Fragment duration %"PRId64" is longer than Segment duration %"PRId64"\n", os->frag_duration, os->seg_duration); return AVERROR(EINVAL); } if (os->frag_type == FRAG_TYPE_PFRAMES && (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO || !os->parser)) { if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !os->parser) - av_log(s, AV_LOG_WARNING, "frag_type set to P-Frame reordering, but no parser found for stream %d\n", - i); + av_log(s, AV_LOG_WARNING, "frag_type set to P-Frame reordering, but no parser found for stream %d\n", i); os->frag_type = c->streaming ? FRAG_TYPE_EVERY_FRAME : FRAG_TYPE_NONE; } if (os->frag_type != FRAG_TYPE_PFRAMES && as->trick_idx < 0) @@ -1646,8 +1628,8 @@ static int dash_init(AVFormatContext *s) { if (os->segment_type == SEGMENT_TYPE_MP4) { if (c->streaming) - // skip_sidx : Reduce bitrate overhead - // skip_trailer : Avoids growing memory usage with time + // skip_sidx : Reduce bitrate overhead + // skip_trailer : Avoids growing memory usage with time av_dict_set(&opts, "movflags", "+dash+delay_moov+skip_sidx+skip_trailer", AV_DICT_APPEND); else { if (c->global_sidx) @@ -1704,16 +1686,14 @@ static int dash_init(AVFormatContext *s) { if (st->sample_aspect_ratio.num) os->sar = st->sample_aspect_ratio; else - os->sar = (AVRational){1, 1}; + os->sar = (AVRational){1,1}; av_reduce(&par.num, &par.den, - st->codecpar->width * (int64_t) os->sar.num, - st->codecpar->height * (int64_t) os->sar.den, + st->codecpar->width * (int64_t)os->sar.num, + st->codecpar->height * (int64_t)os->sar.den, 1024 * 1024); if (as->par.num && av_cmp_q(par, as->par)) { - av_log(s, AV_LOG_ERROR, - "Conflicting stream aspect ratios values in Adaptation Set %d. Please ensure all adaptation sets have the same aspect ratio\n", - os->as_idx); + av_log(s, AV_LOG_ERROR, "Conflicting stream aspect ratios values in Adaptation Set %d. Please ensure all adaptation sets have the same aspect ratio\n", os->as_idx); return AVERROR(EINVAL); } as->par = par; @@ -1732,7 +1712,6 @@ static int dash_init(AVFormatContext *s) { c->nr_of_streams_to_flush++; } - if (!c->has_video && c->seg_duration <= 0) { av_log(s, AV_LOG_WARNING, "no video stream and no seg duration set\n"); return AVERROR(EINVAL); @@ -1746,7 +1725,8 @@ static int dash_init(AVFormatContext *s) { return 0; } -static int dash_write_header(AVFormatContext *s) { +static int dash_write_header(AVFormatContext *s) +{ DASHContext *c = s->priv_data; int i, ret; for (i = 0; i < s->nb_streams; i++) { @@ -1755,6 +1735,7 @@ static int dash_write_header(AVFormatContext *s) { av_dict_copy(&os->ctx->metadata, s->streams[i]->metadata, 0); if ((ret = avformat_write_header(os->ctx, NULL)) < 0) return ret; + // 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. @@ -1768,13 +1749,14 @@ static int dash_write_header(AVFormatContext *s) { static int add_segment(OutputStream *os, const char *file, int64_t time, int64_t duration, int64_t start_pos, int64_t range_length, - int64_t index_length, int next_exp_index) { + int64_t index_length, int next_exp_index) +{ int err; Segment *seg; if (os->nb_segments >= os->segments_size) { os->segments_size = (os->segments_size + 1) * 2; if ((err = av_reallocp_array(&os->segments, sizeof(*os->segments), - os->segments_size)) < 0) { + os->segments_size)) < 0) { os->segments_size = 0; os->nb_segments = 0; return err; @@ -1786,8 +1768,7 @@ static int add_segment(OutputStream *os, const char *file, av_strlcpy(seg->file, file, sizeof(seg->file)); seg->time = time; seg->duration = duration; - if (seg->time < 0) { - // If pts<0, it is expected to be cut away with an edit list + if (seg->time < 0) { // If pts<0, it is expected to be cut away with an edit list seg->duration += seg->time; seg->time = 0; } @@ -1805,7 +1786,8 @@ static int add_segment(OutputStream *os, const char *file, return 0; } -static void write_styp(AVIOContext *pb) { +static void write_styp(AVIOContext *pb) +{ avio_wb32(pb, 24); ffio_wfourcc(pb, "styp"); ffio_wfourcc(pb, "msdh"); @@ -1815,7 +1797,8 @@ static void write_styp(AVIOContext *pb) { } static void find_index_range(AVFormatContext *s, const char *full_path, - int64_t pos, int *index_length) { + int64_t pos, int *index_length) +{ uint8_t buf[8]; AVIOContext *pb; int ret; @@ -1837,7 +1820,8 @@ static void find_index_range(AVFormatContext *s, const char *full_path, } static int update_stream_extradata(AVFormatContext *s, OutputStream *os, - AVPacket *pkt, AVRational *frame_rate) { + AVPacket *pkt, AVRational *frame_rate) +{ AVCodecParameters *par = os->ctx->streams[0]->codecpar; uint8_t *extradata; size_t extradata_size; @@ -1882,12 +1866,13 @@ static void dashenc_delete_file(AVFormatContext *s, char *filename) { int res = ffurl_delete(filename); if (res < 0) { av_log(s, (res == AVERROR(ENOENT) ? AV_LOG_WARNING : AV_LOG_ERROR), - "failed to delete %s: %s\n", filename, av_err2str(res)); + "failed to delete %s: %s\n", filename, av_err2str(res)); } } } -static int dashenc_delete_segment_file(AVFormatContext *s, const char *file) { +static int dashenc_delete_segment_file(AVFormatContext *s, const char* file) +{ DASHContext *c = s->priv_data; AVBPrint buf; @@ -1906,7 +1891,8 @@ static int dashenc_delete_segment_file(AVFormatContext *s, const char *file) { return 0; } -static inline void dashenc_delete_media_segments(AVFormatContext *s, OutputStream *os, int remove_count) { +static inline void dashenc_delete_media_segments(AVFormatContext *s, OutputStream *os, int remove_count) +{ for (int i = 0; i < remove_count; ++i) { dashenc_delete_segment_file(s, os->segments[i]->file); @@ -1918,7 +1904,8 @@ static inline void dashenc_delete_media_segments(AVFormatContext *s, OutputStrea memmove(os->segments, os->segments + remove_count, os->nb_segments * sizeof(*os->segments)); } -static int dash_flush(AVFormatContext *s, int final, int stream) { +static int dash_flush(AVFormatContext *s, int final, int stream) +{ DASHContext *c = s->priv_data; int i, ret = 0; @@ -1997,10 +1984,8 @@ static int dash_flush(AVFormatContext *s, int final, int stream) { if (!os->bit_rate && !os->first_segment_bit_rate) { os->first_segment_bit_rate = (int64_t) range_length * 8 * AV_TIME_BASE / duration; } - add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length, - next_exp_index); - av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, - os->full_path); + add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length, next_exp_index); + av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, os->full_path); os->pos += range_length; } @@ -2033,6 +2018,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream) { seg->start_pos += sidx_size; } } + } } } @@ -2052,17 +2038,18 @@ static int dash_flush(AVFormatContext *s, int final, int stream) { return ret; } -static int dash_parse_prft(DASHContext *c, AVPacket *pkt) { +static int dash_parse_prft(DASHContext *c, AVPacket *pkt) +{ OutputStream *os = &c->streams[pkt->stream_index]; AVProducerReferenceTime *prft; size_t side_data_size; - prft = (AVProducerReferenceTime *) av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &side_data_size); + prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &side_data_size); if (!prft || side_data_size != sizeof(AVProducerReferenceTime) || (prft->flags && prft->flags != 24)) { // No encoder generated or user provided capture time AVProducerReferenceTime side data. Instead // of letting the mov muxer generate one, do it here so we can also use it for the manifest. - prft = (AVProducerReferenceTime *) av_packet_new_side_data(pkt, AV_PKT_DATA_PRFT, - sizeof(AVProducerReferenceTime)); + prft = (AVProducerReferenceTime *)av_packet_new_side_data(pkt, AV_PKT_DATA_PRFT, + sizeof(AVProducerReferenceTime)); if (!prft) return AVERROR(ENOMEM); prft->wallclock = av_gettime(); @@ -2077,7 +2064,8 @@ static int dash_parse_prft(DASHContext *c, AVPacket *pkt) { return 0; } -static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) { +static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) +{ DASHContext *c = s->priv_data; AVStream *st = s->streams[pkt->stream_index]; OutputStream *os = &c->streams[pkt->stream_index]; @@ -2104,7 +2092,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) { if (os->first_pts == AV_NOPTS_VALUE && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) { pkt->pts -= pkt->dts; - pkt->dts = 0; + pkt->dts = 0; } if (c->write_prft) { @@ -2135,16 +2123,16 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) { int64_t frame_duration = 0; switch (os->frag_type) { - case FRAG_TYPE_DURATION: - frame_duration = os->frag_duration; - break; - case FRAG_TYPE_EVERY_FRAME: - frame_duration = av_rescale_q(pkt->duration, st->time_base, AV_TIME_BASE_Q); - break; + case FRAG_TYPE_DURATION: + frame_duration = os->frag_duration; + break; + case FRAG_TYPE_EVERY_FRAME: + frame_duration = av_rescale_q(pkt->duration, st->time_base, AV_TIME_BASE_Q); + break; } - os->availability_time_offset = ((double) os->seg_duration - - frame_duration) / AV_TIME_BASE; + os->availability_time_offset = ((double) os->seg_duration - + frame_duration) / AV_TIME_BASE; as->max_frag_duration = FFMAX(frame_duration, as->max_frag_duration); } @@ -2174,18 +2162,18 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) { seg_end_duration, AV_TIME_BASE_Q) >= 0) { if (!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { c->last_duration = av_rescale_q(pkt->pts - os->start_pts, - st->time_base, - AV_TIME_BASE_Q); + st->time_base, + AV_TIME_BASE_Q); c->total_duration = av_rescale_q(pkt->pts - os->first_pts, - st->time_base, - AV_TIME_BASE_Q); + st->time_base, + AV_TIME_BASE_Q); if ((!c->use_timeline || !c->use_template) && os->last_duration) { - if (c->last_duration < os->last_duration * 9 / 10 || - c->last_duration > os->last_duration * 11 / 10) { + if (c->last_duration < os->last_duration*9/10 || + c->last_duration > os->last_duration*11/10) { av_log(s, AV_LOG_WARNING, - "Segment durations differ too much, enable use_timeline " - "and use_template, or keep a stricter keyframe interval\n"); + "Segment durations differ too much, enable use_timeline " + "and use_template, or keep a stricter keyframe interval\n"); } } } @@ -2229,14 +2217,13 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) { int64_t frag_duration = av_rescale_q(os->total_pkt_duration, st->time_base, AV_TIME_BASE_Q); os->availability_time_offset = ((double) os->seg_duration - - frag_duration) / AV_TIME_BASE; - as->max_frag_duration = FFMAX(frag_duration, as->max_frag_duration); + frag_duration) / AV_TIME_BASE; + as->max_frag_duration = FFMAX(frag_duration, as->max_frag_duration); } } } - if (pkt->flags & AV_PKT_FLAG_KEY && (os->packets_written || os->nb_segments) && !os->gop_size && as->trick_idx < - 0) { + if (pkt->flags & AV_PKT_FLAG_KEY && (os->packets_written || os->nb_segments) && !os->gop_size && as->trick_idx < 0) { os->gop_size = os->last_duration + av_rescale_q(os->total_pkt_duration, st->time_base, AV_TIME_BASE_Q); c->max_gop_size = FFMAX(c->max_gop_size, os->gop_size); } @@ -2292,7 +2279,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) { int len = 0; uint8_t *buf = NULL; avio_flush(os->ctx->pb); - len = avio_get_dyn_buf(os->ctx->pb, &buf); + len = avio_get_dyn_buf (os->ctx->pb, &buf); if (os->out) { avio_write(os->out, buf + os->written_len, len - os->written_len); avio_flush(os->out); @@ -2303,7 +2290,8 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) { return ret; } -static int dash_write_trailer(AVFormatContext *s) { +static int dash_write_trailer(AVFormatContext *s) +{ DASHContext *c = s->priv_data; int i; @@ -2345,7 +2333,8 @@ static int dash_write_trailer(AVFormatContext *s) { } static int dash_check_bitstream(AVFormatContext *s, AVStream *st, - const AVPacket *avpkt) { + const AVPacket *avpkt) +{ DASHContext *c = s->priv_data; OutputStream *os = &c->streams[st->index]; AVFormatContext *oc = os->ctx; @@ -2354,9 +2343,9 @@ static int dash_check_bitstream(AVFormatContext *s, AVStream *st, int ret; ret = ffofmt(oc->oformat)->check_bitstream(oc, ost, avpkt); if (ret == 1) { - FFStream *const sti = ffstream(st); + FFStream *const sti = ffstream(st); FFStream *const osti = ffstream(ost); - sti->bsfc = osti->bsfc; + sti->bsfc = osti->bsfc; osti->bsfc = NULL; } return ret; @@ -2367,204 +2356,74 @@ static int dash_check_bitstream(AVFormatContext *s, AVStream *st, #define OFFSET(x) offsetof(DASHContext, x) #define E AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { - "adaptation_sets", "Adaptation sets. Syntax: id=0,streams=0,1,2 id=1,streams=3,4 and so on", - OFFSET(adaptation_sets), AV_OPT_TYPE_STRING, {0}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM - }, - { - "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, .unit = "segment_type" - }, - { - "auto", "select segment file format based on codec", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_AUTO}, 0, - UINT_MAX, E, .unit = "segment_type" - }, - { - "mp4", "make segment file in ISOBMFF format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_MP4}, 0, UINT_MAX, E, - .unit = "segment_type" - }, - { - "webm", "make segment file in WebM format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_WEBM}, 0, UINT_MAX, E, - .unit = "segment_type" - }, - { - "extra_window_size", "number of segments kept outside of the manifest before removing from disk", - OFFSET(extra_window_size), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E - }, - { - "format_options", "set list of options for the container format (mp4/webm) used for dash", - OFFSET(format_options), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, E - }, - { - "frag_duration", "fragment duration (in seconds, fractional value can be set)", OFFSET(frag_duration), - AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, INT_MAX, E - }, - { - "frag_type", "set type of interval for fragments", OFFSET(frag_type), AV_OPT_TYPE_INT, {.i64 = FRAG_TYPE_NONE}, - 0, FRAG_TYPE_NB - 1, E, .unit = "frag_type" - }, - { - "none", "one fragment per segment", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_NONE}, 0, UINT_MAX, E, - .unit = "frag_type" - }, - { - "every_frame", "fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_EVERY_FRAME}, 0, UINT_MAX, E, - .unit = "frag_type" - }, - { - "duration", "fragment at specific time intervals", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_DURATION}, 0, - UINT_MAX, E, .unit = "frag_type" - }, - { - "pframes", "fragment at keyframes and following P-Frame reordering (Video only, experimental)", 0, - AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_PFRAMES}, 0, UINT_MAX, E, .unit = "frag_type" - }, - { - "global_sidx", "Write global SIDX atom. Applicable only for single file, mp4 output, non-streaming mode", - OFFSET(global_sidx), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E - }, - { - "hls_master_name", "HLS master playlist name", OFFSET(hls_master_name), AV_OPT_TYPE_STRING, - {.str = "master.m3u8"}, 0, 0, E - }, - { - "hls_playlist", "Generate HLS playlist files(master.m3u8, media_%d.m3u8)", OFFSET(hls_playlist), - AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E - }, - {"http_opts", "HTTP protocol options", OFFSET(http_opts), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, E}, - { - "http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, - 1, E - }, - { - "http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent), AV_OPT_TYPE_STRING, - {.str = NULL}, 0, 0, E - }, - { - "ignore_io_errors", "Ignore IO errors during open and write. Useful for long-duration runs with network output", - OFFSET(ignore_io_errors), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E - }, - { - "index_correction", "Enable/Disable segment index correction logic", OFFSET(index_correction), AV_OPT_TYPE_BOOL, - {.i64 = 0}, 0, 1, E - }, - { - "init_seg_name", "DASH-templated name to used for the initialization segment", OFFSET(init_seg_name), - AV_OPT_TYPE_STRING, {.str = "init-stream$RepresentationID$.$ext$"}, 0, 0, E - }, - { - "ldash", "Enable Low-latency dash. Constrains the value of a few elements", OFFSET(ldash), AV_OPT_TYPE_BOOL, - {.i64 = 0}, 0, 1, E - }, - { - "lhls", "Enable Low-latency HLS(Experimental). Adds #EXT-X-PREFETCH tag with current segment's URI", - OFFSET(lhls), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E - }, - { - "master_m3u8_publish_rate", "Publish master playlist every after this many segment intervals", - OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT_MAX, E - }, - { - "max_playback_rate", "Set desired maximum playback rate", OFFSET(max_playback_rate), AV_OPT_TYPE_RATIONAL, - {.dbl = 1.0}, 0.5, 1.5, E - }, - { - "media_seg_name", "DASH-templated name to used for the media segments", OFFSET(media_seg_name), - AV_OPT_TYPE_STRING, {.str = "chunk-stream$RepresentationID$-$Number%05d$.$ext$"}, 0, 0, E - }, - {"method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, - { - "min_playback_rate", "Set desired minimum playback rate", OFFSET(min_playback_rate), AV_OPT_TYPE_RATIONAL, - {.dbl = 1.0}, 0.5, 1.5, E - }, - { - "mpd_profile", "Set profiles. Elements and values used in the manifest may be constrained by them", - OFFSET(profile), AV_OPT_TYPE_FLAGS, {.i64 = MPD_PROFILE_DASH}, 0, UINT_MAX, E, .unit = "mpd_profile" - }, - { - "dash", "MPEG-DASH ISO Base media file format live profile", 0, AV_OPT_TYPE_CONST, {.i64 = MPD_PROFILE_DASH}, 0, - UINT_MAX, E, .unit = "mpd_profile" - }, - { - "dvb_dash", "DVB-DASH profile", 0, AV_OPT_TYPE_CONST, {.i64 = MPD_PROFILE_DVB}, 0, UINT_MAX, E, - .unit = "mpd_profile" - }, - { - "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, - 1, E - }, - { - "seg_duration", "segment duration (in seconds, fractional value can be set)", OFFSET(seg_duration), - AV_OPT_TYPE_DURATION, {.i64 = 5000000}, 0, INT_MAX, E - }, - { - "single_file", "Store all segments in one file, accessed using byte ranges", OFFSET(single_file), - AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E - }, - { - "single_file_name", - "DASH-templated name to be used for baseURL. Implies storing all segments in one file, accessed using byte ranges", - OFFSET(single_file_name), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E - }, - { - "streaming", "Enable/Disable streaming mode of output. Each frame will be moof fragment", OFFSET(streaming), - AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E - }, - { - "target_latency", "Set desired target latency for Low-latency dash", OFFSET(target_latency), - AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, INT_MAX, E - }, - { - "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, - INT_MAX, .flags = E - }, - { - "update_period", "Set the mpd update interval", OFFSET(update_period), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, - INT64_MAX, E - }, - { - "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_BOOL, - {.i64 = 1}, 0, 1, E - }, - { - "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, - 1, E - }, - { - "utc_timing_url", "URL of the page that will return the UTC timestamp in ISO format", OFFSET(utc_timing_url), - AV_OPT_TYPE_STRING, {0}, 0, 0, E - }, - { - "window_size", "number of segments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, - INT_MAX, E - }, - { - "write_prft", "Write producer reference time element", OFFSET(write_prft), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, - E - }, - {NULL}, + { "adaptation_sets", "Adaptation sets. Syntax: id=0,streams=0,1,2 id=1,streams=3,4 and so on", OFFSET(adaptation_sets), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, + { "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, .unit = "segment_type"}, + { "auto", "select segment file format based on codec", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_AUTO }, 0, UINT_MAX, E, .unit = "segment_type"}, + { "mp4", "make segment file in ISOBMFF format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_MP4 }, 0, UINT_MAX, E, .unit = "segment_type"}, + { "webm", "make segment file in WebM format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_WEBM }, 0, UINT_MAX, E, .unit = "segment_type"}, + { "extra_window_size", "number of segments kept outside of the manifest before removing from disk", OFFSET(extra_window_size), AV_OPT_TYPE_INT, { .i64 = 5 }, 0, INT_MAX, E }, + { "format_options","set list of options for the container format (mp4/webm) used for dash", OFFSET(format_options), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, E}, + { "frag_duration", "fragment duration (in seconds, fractional value can be set)", OFFSET(frag_duration), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT_MAX, E }, + { "frag_type", "set type of interval for fragments", OFFSET(frag_type), AV_OPT_TYPE_INT, {.i64 = FRAG_TYPE_NONE }, 0, FRAG_TYPE_NB - 1, E, .unit = "frag_type"}, + { "none", "one fragment per segment", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_NONE }, 0, UINT_MAX, E, .unit = "frag_type"}, + { "every_frame", "fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_EVERY_FRAME }, 0, UINT_MAX, E, .unit = "frag_type"}, + { "duration", "fragment at specific time intervals", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_DURATION }, 0, UINT_MAX, E, .unit = "frag_type"}, + { "pframes", "fragment at keyframes and following P-Frame reordering (Video only, experimental)", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_PFRAMES }, 0, UINT_MAX, E, .unit = "frag_type"}, + { "global_sidx", "Write global SIDX atom. Applicable only for single file, mp4 output, non-streaming mode", OFFSET(global_sidx), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "hls_master_name", "HLS master playlist name", OFFSET(hls_master_name), AV_OPT_TYPE_STRING, {.str = "master.m3u8"}, 0, 0, E }, + { "hls_playlist", "Generate HLS playlist files(master.m3u8, media_%d.m3u8)", OFFSET(hls_playlist), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "http_opts", "HTTP protocol options", OFFSET(http_opts), AV_OPT_TYPE_DICT, { .str = NULL }, 0, 0, E }, + { "http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, + { "http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + { "ignore_io_errors", "Ignore IO errors during open and write. Useful for long-duration runs with network output", OFFSET(ignore_io_errors), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "index_correction", "Enable/Disable segment index correction logic", OFFSET(index_correction), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "init_seg_name", "DASH-templated name to used for the initialization segment", OFFSET(init_seg_name), AV_OPT_TYPE_STRING, {.str = "init-stream$RepresentationID$.$ext$"}, 0, 0, E }, + { "ldash", "Enable Low-latency dash. Constrains the value of a few elements", OFFSET(ldash), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "lhls", "Enable Low-latency HLS(Experimental). Adds #EXT-X-PREFETCH tag with current segment's URI", OFFSET(lhls), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "master_m3u8_publish_rate", "Publish master playlist every after this many segment intervals", OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT_MAX, E}, + { "max_playback_rate", "Set desired maximum playback rate", OFFSET(max_playback_rate), AV_OPT_TYPE_RATIONAL, { .dbl = 1.0 }, 0.5, 1.5, E }, + { "media_seg_name", "DASH-templated name to used for the media segments", OFFSET(media_seg_name), AV_OPT_TYPE_STRING, {.str = "chunk-stream$RepresentationID$-$Number%05d$.$ext$"}, 0, 0, E }, + { "method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, + { "min_playback_rate", "Set desired minimum playback rate", OFFSET(min_playback_rate), AV_OPT_TYPE_RATIONAL, { .dbl = 1.0 }, 0.5, 1.5, E }, + { "mpd_profile", "Set profiles. Elements and values used in the manifest may be constrained by them", OFFSET(profile), AV_OPT_TYPE_FLAGS, {.i64 = MPD_PROFILE_DASH }, 0, UINT_MAX, E, .unit = "mpd_profile"}, + { "dash", "MPEG-DASH ISO Base media file format live profile", 0, AV_OPT_TYPE_CONST, {.i64 = MPD_PROFILE_DASH }, 0, UINT_MAX, E, .unit = "mpd_profile"}, + { "dvb_dash", "DVB-DASH profile", 0, AV_OPT_TYPE_CONST, {.i64 = MPD_PROFILE_DVB }, 0, UINT_MAX, E, .unit = "mpd_profile"}, + { "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "seg_duration", "segment duration (in seconds, fractional value can be set)", OFFSET(seg_duration), AV_OPT_TYPE_DURATION, { .i64 = 5000000 }, 0, INT_MAX, E }, + { "single_file", "Store all segments in one file, accessed using byte ranges", OFFSET(single_file), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "single_file_name", "DASH-templated name to be used for baseURL. Implies storing all segments in one file, accessed using byte ranges", OFFSET(single_file_name), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, + { "streaming", "Enable/Disable streaming mode of output. Each frame will be moof fragment", OFFSET(streaming), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "target_latency", "Set desired target latency for Low-latency dash", OFFSET(target_latency), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT_MAX, E }, + { "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E }, + { "update_period", "Set the mpd update interval", OFFSET(update_period), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, E}, + { "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E }, + { "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E }, + { "utc_timing_url", "URL of the page that will return the UTC timestamp in ISO format", OFFSET(utc_timing_url), AV_OPT_TYPE_STRING, { 0 }, 0, 0, E }, + { "window_size", "number of segments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E }, + { "write_prft", "Write producer reference time element", OFFSET(write_prft), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, E}, + { NULL }, }; static const AVClass dash_class = { .class_name = "dash muxer", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, }; const FFOutputFormat ff_dash_muxer = { - .p.name = "dash", - .p.long_name = NULL_IF_CONFIG_SMALL("DASH Muxer"), - .p.extensions = "mpd", - .p.audio_codec = AV_CODEC_ID_AAC, - .p.video_codec = AV_CODEC_ID_H264, - .p.flags = AVFMT_GLOBALHEADER | AVFMT_NOFILE | AVFMT_TS_NEGATIVE, - .p.priv_class = &dash_class, + .p.name = "dash", + .p.long_name = NULL_IF_CONFIG_SMALL("DASH Muxer"), + .p.extensions = "mpd", + .p.audio_codec = AV_CODEC_ID_AAC, + .p.video_codec = AV_CODEC_ID_H264, + .p.flags = AVFMT_GLOBALHEADER | AVFMT_NOFILE | AVFMT_TS_NEGATIVE, + .p.priv_class = &dash_class, .priv_data_size = sizeof(DASHContext), - .init = dash_init, - .write_header = dash_write_header, - .write_packet = dash_write_packet, - .write_trailer = dash_write_trailer, - .deinit = dash_free, + .init = dash_init, + .write_header = dash_write_header, + .write_packet = dash_write_packet, + .write_trailer = dash_write_trailer, + .deinit = dash_free, .check_bitstream = dash_check_bitstream, }; -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org