[FFmpeg-devel] [PATCH] Add init_program_date_time so start time can be specified
--- doc/muxers.texi | 3 +++ libavformat/hlsenc.c | 7 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index f6071484ff..87c19a5cb9 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -1086,6 +1086,9 @@ seeking. This flag should be used with the @code{hls_time} option. @item program_date_time Generate @code{EXT-X-PROGRAM-DATE-TIME} tags. +@item init_program_date_time +Time to start program date time at. + @item second_level_segment_index Makes it possible to use segment indexes as %%d in hls_segment_filename expression besides date/time values when strftime is on. diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 4ef84c05c1..474322cc21 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -28,6 +28,8 @@ #include #endif +#include "float.h" + #include "libavutil/avassert.h" #include "libavutil/mathematics.h" #include "libavutil/avstring.h" @@ -212,6 +214,8 @@ typedef struct HLSContext { int64_t recording_time; int64_t max_seg_size; // every segment file max size +double init_program_date_time; + char *baseurl; char *vtt_format_options_str; char *subtitle_filename; @@ -2867,7 +2871,7 @@ static int hls_init(AVFormatContext *s) char *p = NULL; int http_base_proto = ff_is_http_proto(s->url); int fmp4_init_filename_len = strlen(hls->fmp4_init_filename) + 1; -double initial_program_date_time = av_gettime() / 100.0; +double initial_program_date_time = hls->init_program_date_time ? hls->init_program_date_time : av_gettime() / 100.0; if (hls->use_localtime) { pattern = get_default_pattern_localtime_fmt(s); @@ -3141,6 +3145,7 @@ static const AVOption options[] = { {"split_by_time", "split the hls segment by time which user set by hls_time", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SPLIT_BY_TIME }, 0, UINT_MAX, E, "flags"}, {"append_list", "append the new segments into old hls segment list", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_APPEND_LIST }, 0, UINT_MAX, E, "flags"}, {"program_date_time", "add EXT-X-PROGRAM-DATE-TIME", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PROGRAM_DATE_TIME }, 0, UINT_MAX, E, "flags"}, +{"init_program_date_time", "Time to start program date time at", OFFSET(init_program_date_time), AV_OPT_TYPE_DOUBLE, {.dbl = 0 }, 0, DBL_MAX, E}, {"second_level_segment_index", "include segment index in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_INDEX }, 0, UINT_MAX, E, "flags"}, {"second_level_segment_duration", "include segment duration in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_DURATION }, 0, UINT_MAX, E, "flags"}, {"second_level_segment_size", "include segment size in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_SIZE }, 0, UINT_MAX, E, "flags"}, -- 2.39.2 (Apple Git-143) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH] Add init_program_date_time so start time can be specified
--- doc/muxers.texi | 3 +++ libavformat/hlsenc.c | 41 + 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index f6071484ff..87c19a5cb9 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -1086,6 +1086,9 @@ seeking. This flag should be used with the @code{hls_time} option. @item program_date_time Generate @code{EXT-X-PROGRAM-DATE-TIME} tags. +@item init_program_date_time +Time to start program date time at. + @item second_level_segment_index Makes it possible to use segment indexes as %%d in hls_segment_filename expression besides date/time values when strftime is on. diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 4ef84c05c1..5dfff6b2b6 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -212,6 +212,8 @@ typedef struct HLSContext { int64_t recording_time; int64_t max_seg_size; // every segment file max size +char *init_program_date_time; + char *baseurl; char *vtt_format_options_str; char *subtitle_filename; @@ -1192,6 +1194,25 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, return 0; } +static double parse_iso8601(const char *ptr) { +struct tm program_date_time; +int y,M,d,h,m,s; +double ms; +if (sscanf(ptr, "%d-%d-%dT%d:%d:%d.%lf", &y, &M, &d, &h, &m, &s, &ms) != 7) { +return -1; +} + +program_date_time.tm_year = y - 1900; +program_date_time.tm_mon = M - 1; +program_date_time.tm_mday = d; +program_date_time.tm_hour = h; +program_date_time.tm_min = m; +program_date_time.tm_sec = s; +program_date_time.tm_isdst = -1; + +return mktime(&program_date_time) + (double)(ms / 1000); +} + static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs) { HLSContext *hls = s->priv_data; @@ -1257,24 +1278,11 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs } } } else if (av_strstart(line, "#EXT-X-PROGRAM-DATE-TIME:", &ptr)) { -struct tm program_date_time; -int y,M,d,h,m,s; -double ms; -if (sscanf(ptr, "%d-%d-%dT%d:%d:%d.%lf", &y, &M, &d, &h, &m, &s, &ms) != 7) { +discont_program_date_time = parse_iso8601(ptr); +if (discont_program_date_time < 0) { ret = AVERROR_INVALIDDATA; goto fail; } - -program_date_time.tm_year = y - 1900; -program_date_time.tm_mon = M - 1; -program_date_time.tm_mday = d; -program_date_time.tm_hour = h; -program_date_time.tm_min = m; -program_date_time.tm_sec = s; -program_date_time.tm_isdst = -1; - -discont_program_date_time = mktime(&program_date_time); -discont_program_date_time += (double)(ms / 1000); } else if (av_strstart(line, "#", NULL)) { continue; } else if (line[0]) { @@ -2867,7 +2875,7 @@ static int hls_init(AVFormatContext *s) char *p = NULL; int http_base_proto = ff_is_http_proto(s->url); int fmp4_init_filename_len = strlen(hls->fmp4_init_filename) + 1; -double initial_program_date_time = av_gettime() / 100.0; +double initial_program_date_time = hls->init_program_date_time ? parse_iso8601(hls->init_program_date_time) : av_gettime() / 100.0; if (hls->use_localtime) { pattern = get_default_pattern_localtime_fmt(s); @@ -3141,6 +3149,7 @@ static const AVOption options[] = { {"split_by_time", "split the hls segment by time which user set by hls_time", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SPLIT_BY_TIME }, 0, UINT_MAX, E, "flags"}, {"append_list", "append the new segments into old hls segment list", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_APPEND_LIST }, 0, UINT_MAX, E, "flags"}, {"program_date_time", "add EXT-X-PROGRAM-DATE-TIME", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PROGRAM_DATE_TIME }, 0, UINT_MAX, E, "flags"}, +{"init_program_date_time", "Time to start program date time at", OFFSET(init_program_date_time), AV_OPT_TYPE_STRING, .flags = E}, {"second_level_segment_index", "include segment index in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_INDEX }, 0, UINT_MAX, E, "flags"}, {"second_level_segment_duration", "include segment duration in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_DURATION }, 0, UINT_MAX, E, "flags"}, {"second_level_segment_size", "include segment size in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_SIZE }, 0, UINT_MAX, E, "flags"}, -- 2.39.2 (Apple Git-143) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, vi
[FFmpeg-devel] [PATCH] avformat/hlsenc: Add CHANNELS to EXT-X-MEDIA for Audio
--- libavformat/dashenc.c | 3 ++- libavformat/hlsenc.c | 8 +++- libavformat/hlsplaylist.c | 5 - libavformat/hlsplaylist.h | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index 96f4a5fbdf..15f700acbc 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -1284,7 +1284,8 @@ static int write_manifest(AVFormatContext *s, int final) continue; get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i); ff_hls_write_audio_rendition(c->m3u8_out, audio_group, - playlist_file, NULL, i, is_default); + playlist_file, NULL, i, is_default, + s->streams[i]->codecpar->ch_layout.nb_channels); max_audio_bitrate = FFMAX(st->codecpar->bit_rate + os->muxer_overhead, max_audio_bitrate); if (!av_strnstr(audio_codec_str, os->codec_str, sizeof(audio_codec_str))) { diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 4ef84c05c1..7dfb8d0a9f 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -1386,6 +1386,7 @@ static int create_master_playlist(AVFormatContext *s, int is_file_proto = proto && !strcmp(proto, "file"); int use_temp_file = is_file_proto && ((hls->flags & HLS_TEMP_FILE) || hls->master_publish_rate); char temp_filename[MAX_URL_SIZE]; +int nb_channels; input_vs->m3u8_created = 1; if (!hls->master_m3u8_created) { @@ -1434,8 +1435,13 @@ static int create_master_playlist(AVFormatContext *s, av_log(s, AV_LOG_ERROR, "Unable to find relative URL\n"); goto fail; } +nb_channels = 0; +for (j = 0; j < vs->nb_streams; j++) +if (vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) +if (vs->streams[j]->codecpar->ch_layout.nb_channels > nb_channels) +nb_channels = vs->streams[j]->codecpar->ch_layout.nb_channels; -ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, m3u8_rel_name, vs->language, i, hls->has_default_key ? vs->is_default : 1); +ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, m3u8_rel_name, vs->language, i, hls->has_default_key ? vs->is_default : 1, nb_channels); } /* For variant streams with video add #EXT-X-STREAM-INF tag with attributes*/ diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c index 2bf05f3c7c..4f35d0388f 100644 --- a/libavformat/hlsplaylist.c +++ b/libavformat/hlsplaylist.c @@ -39,7 +39,7 @@ void ff_hls_write_playlist_version(AVIOContext *out, int version) void ff_hls_write_audio_rendition(AVIOContext *out, const char *agroup, const char *filename, const char *language, - int name_id, int is_default) + int name_id, int is_default, int nb_channels) { if (!out || !agroup || !filename) return; @@ -49,6 +49,9 @@ void ff_hls_write_audio_rendition(AVIOContext *out, const char *agroup, if (language) { avio_printf(out, "LANGUAGE=\"%s\",", language); } +if (nb_channels) { +avio_printf(out, "CHANNELS=\"%d\",", nb_channels); +} avio_printf(out, "URI=\"%s\"\n", filename); } diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h index 1928fe787d..c2744c227c 100644 --- a/libavformat/hlsplaylist.h +++ b/libavformat/hlsplaylist.h @@ -38,7 +38,7 @@ typedef enum { void ff_hls_write_playlist_version(AVIOContext *out, int version); void ff_hls_write_audio_rendition(AVIOContext *out, const char *agroup, const char *filename, const char *language, - int name_id, int is_default); + int name_id, int is_default, int nb_channels); void ff_hls_write_subtitle_rendition(AVIOContext *out, const char *sgroup, const char *filename, const char *language, int name_id, int is_default); -- 2.39.2 (Apple Git-143) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 1/4] avformat/hlsenc: Add init_program_date_time so start time can be specified
--- doc/muxers.texi | 3 +++ libavformat/hlsenc.c | 41 + 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index f6071484ff..87c19a5cb9 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -1086,6 +1086,9 @@ seeking. This flag should be used with the @code{hls_time} option. @item program_date_time Generate @code{EXT-X-PROGRAM-DATE-TIME} tags. +@item init_program_date_time +Time to start program date time at. + @item second_level_segment_index Makes it possible to use segment indexes as %%d in hls_segment_filename expression besides date/time values when strftime is on. diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 4ef84c05c1..5dfff6b2b6 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -212,6 +212,8 @@ typedef struct HLSContext { int64_t recording_time; int64_t max_seg_size; // every segment file max size +char *init_program_date_time; + char *baseurl; char *vtt_format_options_str; char *subtitle_filename; @@ -1192,6 +1194,25 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, return 0; } +static double parse_iso8601(const char *ptr) { +struct tm program_date_time; +int y,M,d,h,m,s; +double ms; +if (sscanf(ptr, "%d-%d-%dT%d:%d:%d.%lf", &y, &M, &d, &h, &m, &s, &ms) != 7) { +return -1; +} + +program_date_time.tm_year = y - 1900; +program_date_time.tm_mon = M - 1; +program_date_time.tm_mday = d; +program_date_time.tm_hour = h; +program_date_time.tm_min = m; +program_date_time.tm_sec = s; +program_date_time.tm_isdst = -1; + +return mktime(&program_date_time) + (double)(ms / 1000); +} + static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs) { HLSContext *hls = s->priv_data; @@ -1257,24 +1278,11 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs } } } else if (av_strstart(line, "#EXT-X-PROGRAM-DATE-TIME:", &ptr)) { -struct tm program_date_time; -int y,M,d,h,m,s; -double ms; -if (sscanf(ptr, "%d-%d-%dT%d:%d:%d.%lf", &y, &M, &d, &h, &m, &s, &ms) != 7) { +discont_program_date_time = parse_iso8601(ptr); +if (discont_program_date_time < 0) { ret = AVERROR_INVALIDDATA; goto fail; } - -program_date_time.tm_year = y - 1900; -program_date_time.tm_mon = M - 1; -program_date_time.tm_mday = d; -program_date_time.tm_hour = h; -program_date_time.tm_min = m; -program_date_time.tm_sec = s; -program_date_time.tm_isdst = -1; - -discont_program_date_time = mktime(&program_date_time); -discont_program_date_time += (double)(ms / 1000); } else if (av_strstart(line, "#", NULL)) { continue; } else if (line[0]) { @@ -2867,7 +2875,7 @@ static int hls_init(AVFormatContext *s) char *p = NULL; int http_base_proto = ff_is_http_proto(s->url); int fmp4_init_filename_len = strlen(hls->fmp4_init_filename) + 1; -double initial_program_date_time = av_gettime() / 100.0; +double initial_program_date_time = hls->init_program_date_time ? parse_iso8601(hls->init_program_date_time) : av_gettime() / 100.0; if (hls->use_localtime) { pattern = get_default_pattern_localtime_fmt(s); @@ -3141,6 +3149,7 @@ static const AVOption options[] = { {"split_by_time", "split the hls segment by time which user set by hls_time", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SPLIT_BY_TIME }, 0, UINT_MAX, E, "flags"}, {"append_list", "append the new segments into old hls segment list", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_APPEND_LIST }, 0, UINT_MAX, E, "flags"}, {"program_date_time", "add EXT-X-PROGRAM-DATE-TIME", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PROGRAM_DATE_TIME }, 0, UINT_MAX, E, "flags"}, +{"init_program_date_time", "Time to start program date time at", OFFSET(init_program_date_time), AV_OPT_TYPE_STRING, .flags = E}, {"second_level_segment_index", "include segment index in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_INDEX }, 0, UINT_MAX, E, "flags"}, {"second_level_segment_duration", "include segment duration in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_DURATION }, 0, UINT_MAX, E, "flags"}, {"second_level_segment_size", "include segment size in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_SIZE }, 0, UINT_MAX, E, "flags"}, -- 2.39.2 (Apple Git-143) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, vi
[FFmpeg-devel] [PATCH 2/4] avformat/hlsenc: Add strftime_prog for using PROGRAM-DATE-TIME in the segment filename
--- libavformat/hlsenc.c | 36 ++-- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 5dfff6b2b6..24a0304f78 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -159,6 +159,7 @@ typedef struct VariantStream { char *m3u8_name; double initial_prog_date_time; +double curr_prog_date_time; char current_segment_final_filename_fmt[MAX_URL_SIZE]; // when renaming segments char *fmp4_init_filename; @@ -208,6 +209,7 @@ typedef struct HLSContext { int use_localtime; ///< flag to expand filename with localtime int use_localtime_mkdir;///< flag to mkdir dirname in timebased filename +int use_localtime_prog; ///< flag to expand filename with prog date time int allowcache; int64_t recording_time; int64_t max_seg_size; // every segment file max size @@ -259,10 +261,9 @@ typedef struct HLSContext { int has_video_m3u8; /* has video stream m3u8 list */ } HLSContext; -static int strftime_expand(const char *fmt, char **dest) +static int strftime_expand_time_t(const char *fmt, const time_t *value, char **dest) { int r = 1; -time_t now0; struct tm *tm, tmpbuf; char *buf; @@ -270,8 +271,7 @@ static int strftime_expand(const char *fmt, char **dest) if (!buf) return AVERROR(ENOMEM); -time(&now0); -tm = localtime_r(&now0, &tmpbuf); +tm = localtime_r(value, &tmpbuf); r = strftime(buf, MAX_URL_SIZE, fmt, tm); if (!r) { av_free(buf); @@ -282,6 +282,19 @@ static int strftime_expand(const char *fmt, char **dest) return r; } +static int strftime_expand(const char *fmt, char **dest) +{ +time_t now0; +time(&now0); +return strftime_expand_time_t(fmt, &now0, dest); +} + +static int strftime_expand_prog(const char *fmt, const double prog_date_time, char **dest) +{ +time_t value = (time_t)prog_date_time; +return strftime_expand_time_t(fmt, &value, dest); +} + static int hlsenc_io_open(AVFormatContext *s, AVIOContext **pb, const char *filename, AVDictionary **options) { @@ -1721,7 +1734,11 @@ static int hls_start(AVFormatContext *s, VariantStream *vs) int r; char *expanded = NULL; -r = strftime_expand(vs->basename, &expanded); +if (c->use_localtime_prog) { +r = strftime_expand_prog(vs->basename, vs->curr_prog_date_time, &expanded); +} else { +r = strftime_expand(vs->basename, &expanded); +} if (r < 0) { av_log(oc, AV_LOG_ERROR, "Could not get segment filename with strftime\n"); return r; @@ -2615,6 +2632,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) if (vs->start_pos || hls->segment_type != SEGMENT_TYPE_FMP4) { double cur_duration = (double)(pkt->pts - vs->end_pts) * st->time_base.num / st->time_base.den; ret = hls_append_segment(s, hls, vs, cur_duration, vs->start_pos, vs->size); +vs->curr_prog_date_time += cur_duration; vs->end_pts = pkt->pts; vs->duration = 0; if (ret < 0) { @@ -2971,6 +2989,7 @@ static int hls_init(AVFormatContext *s) vs->end_pts = AV_NOPTS_VALUE; vs->current_segment_final_filename_fmt[0] = '\0'; vs->initial_prog_date_time = initial_program_date_time; +vs->curr_prog_date_time = initial_program_date_time; for (j = 0; j < vs->nb_streams; j++) { vs->has_video += vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO; @@ -3038,7 +3057,11 @@ static int hls_init(AVFormatContext *s) int r; char *expanded = NULL; -r = strftime_expand(vs->fmp4_init_filename, &expanded); +if (hls->use_localtime_prog) { +r = strftime_expand_prog(vs->fmp4_init_filename, vs->curr_prog_date_time, &expanded); +} else { +r = strftime_expand(vs->fmp4_init_filename, &expanded); +} if (r < 0) { av_log(s, AV_LOG_ERROR, "Could not get segment filename with strftime\n"); return r; @@ -3158,6 +3181,7 @@ static const AVOption options[] = { {"iframes_only", "add EXT-X-I-FRAMES-ONLY, whenever applicable", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_I_FRAMES_ONLY }, 0, UINT_MAX, E, "flags"}, {"strftime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, {"strftime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, +{"strftime_prog", "set filename expanish with program date time", OFFSET(use_localtime_prog), AV_OPT
[FFmpeg-devel] [PATCH 3/4] avformat/hlsenc: Fix name of flag in error message
--- libavformat/hlsenc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 24a0304f78..93c47b631b 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -1013,7 +1013,7 @@ static int sls_flags_filename_process(struct AVFormatContext *s, HLSContext *hls 't', (int64_t)round(duration * HLS_MICROSECOND_UNIT)) < 1) { av_log(hls, AV_LOG_ERROR, "Invalid second level segment filename template '%s', " - "you can try to remove second_level_segment_time flag\n", + "you can try to remove second_level_segment_duration flag\n", vs->avf->url); av_freep(&filename); return AVERROR(EINVAL); @@ -1106,7 +1106,7 @@ static int sls_flag_use_localtime_filename(AVFormatContext *oc, HLSContext *c, V char *filename = NULL; if (replace_int_data_in_filename(&filename, oc->url, 't', 0) < 1) { av_log(c, AV_LOG_ERROR, "Invalid second level segment filename template '%s', " -"you can try to remove second_level_segment_time flag\n", +"you can try to remove second_level_segment_duration flag\n", oc->url); av_freep(&filename); return AVERROR(EINVAL); -- 2.39.2 (Apple Git-143) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 4/4] avformat/hlsenc: Add second_level_segment_microsecond for using %%f to specify microseconds of time in segment filename
--- libavformat/hlsenc.c | 51 +--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 93c47b631b..f613e35984 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -103,6 +103,7 @@ typedef enum HLSFlags { HLS_SECOND_LEVEL_SEGMENT_INDEX = (1 << 8), // include segment index in segment filenames when use_localtime e.g.: %%03d HLS_SECOND_LEVEL_SEGMENT_DURATION = (1 << 9), // include segment duration (microsec) in segment filenames when use_localtime e.g.: %%09t HLS_SECOND_LEVEL_SEGMENT_SIZE = (1 << 10), // include segment size (bytes) in segment filenames when use_localtime e.g.: %%014s +HLS_SECOND_LEVEL_SEGMENT_MICROSECOND = (1 << 15), // include microseconds of localtime in segment filenames when use_localtime e.g.: %%f HLS_TEMP_FILE = (1 << 11), HLS_PERIODIC_REKEY = (1 << 12), HLS_INDEPENDENT_SEGMENTS = (1 << 13), @@ -496,7 +497,7 @@ static int replace_str_data_in_filename(char **s, const char *filename, char pla return found_count; } -static int replace_int_data_in_filename(char **s, const char *filename, char placeholder, int64_t number) +static int replace_int_data_in_filename_forced(char **s, const char *filename, char placeholder, int64_t number, int forced_digits) { const char *p; char c; @@ -521,6 +522,9 @@ static int replace_int_data_in_filename(char **s, const char *filename, char pla nd = nd * 10 + *(p + addchar_count) - '0'; addchar_count++; } +if (forced_digits > nd) { +nd = forced_digits; +} if (*(p + addchar_count) == placeholder) { av_bprintf(&buf, "%0*"PRId64, (number < 0) ? nd : nd++, number); @@ -544,6 +548,11 @@ static int replace_int_data_in_filename(char **s, const char *filename, char pla return found_count; } +static int replace_int_data_in_filename(char **s, const char *filename, char placeholder, int64_t number) +{ +return replace_int_data_in_filename_forced(s, filename, placeholder, number, 0); +} + static void write_styp(AVIOContext *pb) { avio_wb32(pb, 24); @@ -1020,6 +1029,20 @@ static int sls_flags_filename_process(struct AVFormatContext *s, HLSContext *hls } ff_format_set_url(vs->avf, filename); } +if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_MICROSECOND) { +char *filename = NULL; +double mod_res; +if (replace_int_data_in_filename_forced(&filename, vs->avf->url, + 'f', 100 * modf(vs->curr_prog_date_time, &mod_res), 6) < 1) { +av_log(hls, AV_LOG_ERROR, + "Invalid second level segment filename template '%s', " + "you can try to remove second_level_segment_microsecond flag\n", + vs->avf->url); +av_freep(&filename); +return AVERROR(EINVAL); +} +ff_format_set_url(vs->avf, filename); +} } return 0; } @@ -1043,6 +1066,11 @@ static int sls_flag_check_duration_size_index(HLSContext *hls) "second_level_segment_index hls_flag requires strftime to be true\n"); ret = AVERROR(EINVAL); } +if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_MICROSECOND) { +av_log(hls, AV_LOG_ERROR, + "second_level_segment_microsecond hls_flag requires strftime to be true\n"); +ret = AVERROR(EINVAL); +} return ret; } @@ -1063,12 +1091,17 @@ static int sls_flag_check_duration_size(HLSContext *hls, VariantStream *vs) "second_level_segment_size hls_flag works only with file protocol segment names\n"); ret = AVERROR(EINVAL); } +if ((hls->flags & HLS_SECOND_LEVEL_SEGMENT_MICROSECOND) && !segment_renaming_ok) { +av_log(hls, AV_LOG_ERROR, + "second_level_segment_microsecond hls_flag works only with file protocol segment names\n"); +ret = AVERROR(EINVAL); +} return ret; } static void sls_flag_file_rename(HLSContext *hls, VariantStream *vs, char *old_filename) { -if ((hls->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) && +if ((hls->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION | HLS_SECOND_LEVEL_SEGMENT_MICROSECOND)) && strlen(vs->current_segment_final_filename_fmt)) { ff_rename(old_filename, vs->avf->url, hls); } @@ -1088,7 +1121,7 @@ static int sls_flag_use_localtime_filename(AVFormatContext *oc, HLSContext *c, V } ff_format_set_url(oc, filename); } -if (c->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) { +if (c->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION | HLS_SECOND_LEVEL_SEGMENT_MICROS
[FFmpeg-devel] [PATCH] avformat/hlsenc: Handle when fractional seconds not set and error out when init_program_date_time can't be parsed
--- libavformat/hlsenc.c | 26 +++--- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index f613e35984..e1714d4eed 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -1253,9 +1253,11 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, static double parse_iso8601(const char *ptr) { struct tm program_date_time; -int y,M,d,h,m,s; -double ms; -if (sscanf(ptr, "%d-%d-%dT%d:%d:%d.%lf", &y, &M, &d, &h, &m, &s, &ms) != 7) { +int y,M,d,h,m; +double s; +int num_scanned = sscanf(ptr, "%d-%d-%dT%d:%d:%lf", &y, &M, &d, &h, &m, &s); + +if (num_scanned < 6) { return -1; } @@ -1264,10 +1266,10 @@ static double parse_iso8601(const char *ptr) { program_date_time.tm_mday = d; program_date_time.tm_hour = h; program_date_time.tm_min = m; -program_date_time.tm_sec = s; +program_date_time.tm_sec = 0; program_date_time.tm_isdst = -1; -return mktime(&program_date_time) + (double)(ms / 1000); +return mktime(&program_date_time) + s; } static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs) @@ -2937,7 +2939,17 @@ static int hls_init(AVFormatContext *s) char *p = NULL; int http_base_proto = ff_is_http_proto(s->url); int fmp4_init_filename_len = strlen(hls->fmp4_init_filename) + 1; -double initial_program_date_time = hls->init_program_date_time ? parse_iso8601(hls->init_program_date_time) : av_gettime() / 100.0; +double initial_program_date_time; + +if (hls->init_program_date_time) { +initial_program_date_time = parse_iso8601(hls->init_program_date_time); +if (initial_program_date_time < 0) { +av_log(s, AV_LOG_ERROR, "Invalid init_program_date_time\n"); +return AVERROR(EINVAL); +} +} else { +initial_program_date_time = av_gettime() / 100.0; +} if (hls->use_localtime) { pattern = get_default_pattern_localtime_fmt(s); @@ -3216,7 +3228,7 @@ static const AVOption options[] = { {"split_by_time", "split the hls segment by time which user set by hls_time", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SPLIT_BY_TIME }, 0, UINT_MAX, E, "flags"}, {"append_list", "append the new segments into old hls segment list", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_APPEND_LIST }, 0, UINT_MAX, E, "flags"}, {"program_date_time", "add EXT-X-PROGRAM-DATE-TIME", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PROGRAM_DATE_TIME }, 0, UINT_MAX, E, "flags"}, -{"init_program_date_time", "Time to start program date time at", OFFSET(init_program_date_time), AV_OPT_TYPE_STRING, .flags = E}, +{"init_program_date_time", "Time to start program date time at (must be %Y-%m-%dT%H:%M:%S and timezone is ignored)", OFFSET(init_program_date_time), AV_OPT_TYPE_STRING, .flags = E}, {"second_level_segment_index", "include segment index in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_INDEX }, 0, UINT_MAX, E, "flags"}, {"second_level_segment_duration", "include segment duration in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_DURATION }, 0, UINT_MAX, E, "flags"}, {"second_level_segment_size", "include segment size in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_SIZE }, 0, UINT_MAX, E, "flags"}, -- 2.39.2 (Apple Git-143) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH] avformat/hlsenc: Move lrint outside of loop
--- libavformat/hlsenc.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 4ef84c05c1..e59a38b497 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -1538,7 +1538,7 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) { HLSContext *hls = s->priv_data; HLSSegment *en; -int target_duration = 0; +double target_duration = 0; int ret = 0; char temp_filename[MAX_URL_SIZE]; char temp_vtt_filename[MAX_URL_SIZE]; @@ -1589,12 +1589,12 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) for (en = vs->segments; en; en = en->next) { if (target_duration <= en->duration) -target_duration = lrint(en->duration); +target_duration = en->duration; } vs->discontinuity_set = 0; ff_hls_write_playlist_header(byterange_mode ? hls->m3u8_out : vs->out, hls->version, hls->allowcache, - target_duration, sequence, hls->pl_type, hls->flags & HLS_I_FRAMES_ONLY); + lrint(target_duration), sequence, hls->pl_type, hls->flags & HLS_I_FRAMES_ONLY); if ((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && vs->discontinuity_set==0) { avio_printf(byterange_mode ? hls->m3u8_out : vs->out, "#EXT-X-DISCONTINUITY\n"); @@ -1643,7 +1643,7 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) goto fail; } ff_hls_write_playlist_header(hls->sub_m3u8_out, hls->version, hls->allowcache, - target_duration, sequence, PLAYLIST_TYPE_NONE, 0); + lrint(target_duration), sequence, PLAYLIST_TYPE_NONE, 0); for (en = vs->segments; en; en = en->next) { ret = ff_hls_write_file_entry(hls->sub_m3u8_out, 0, byterange_mode, en->duration, 0, en->size, en->pos, -- 2.39.2 (Apple Git-143) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH] avformat/hlsenc: Only append postfix to fmp4 init filename if not in the subdir
--- libavformat/hlsenc.c | 26 +- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 4ef84c05c1..dd1a461cce 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -1931,6 +1931,30 @@ fail: return ret; } +static int validate_subdir(const char *fn) +{ +const char *subdir_name; +char *fn_dup = NULL; +int ret = 0; + +if (!fn) +return AVERROR(EINVAL); + +fn_dup = av_strdup(fn); +if (!fn_dup) +return AVERROR(ENOMEM); +subdir_name = av_dirname(fn_dup); + +if (!av_stristr(subdir_name, "%v")) { +ret = AVERROR(EINVAL); +goto fail; +} + +fail: +av_freep(&fn_dup); +return ret; +} + static int format_name(const char *buf, char **s, int index, const char *varname) { const char *proto, *dir; @@ -3019,7 +3043,7 @@ static int hls_init(AVFormatContext *s) av_freep(&vs->fmp4_init_filename); ret = format_name(hls->fmp4_init_filename, &vs->fmp4_init_filename, i, vs->varname); -} else { +} else if (validate_subdir(s->url) < 0) { ret = append_postfix(vs->fmp4_init_filename, fmp4_init_filename_len, i); } if (ret < 0) -- 2.39.2 (Apple Git-143) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH] avformat/hlsenc: Allow setting master_pl_publish_rate to a negative value to have it write immediately
--- libavformat/hlsenc.c | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 4ef84c05c1..76d8094de6 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -245,7 +245,7 @@ typedef struct HLSContext { char *var_stream_map; /* user specified variant stream map string */ char *cc_stream_map; /* user specified closed caption streams map string */ char *master_pl_name; -unsigned int master_publish_rate; +int master_publish_rate; int http_persistent; AVIOContext *m3u8_out; AVIOContext *sub_m3u8_out; @@ -1388,7 +1388,9 @@ static int create_master_playlist(AVFormatContext *s, char temp_filename[MAX_URL_SIZE]; input_vs->m3u8_created = 1; -if (!hls->master_m3u8_created) { +if (hls->master_publish_rate < 0) { +hls->master_publish_rate = 0; +} else if (!hls->master_m3u8_created) { /* For the first time, wait until all the media playlists are created */ for (i = 0; i < hls->nb_varstreams; i++) if (!hls->var_streams[i].m3u8_created) @@ -3162,7 +3164,7 @@ static const AVOption options[] = { {"var_stream_map", "Variant stream map string", OFFSET(var_stream_map), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0,E}, {"cc_stream_map", "Closed captions stream map string", OFFSET(cc_stream_map), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0,E}, {"master_pl_name", "Create HLS master playlist with this name", OFFSET(master_pl_name), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0,E}, -{"master_pl_publish_rate", "Publish master play list every after this many segment intervals", OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT_MAX, E}, +{"master_pl_publish_rate", "Publish master play list every after this many segment intervals", OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, E}, {"http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, {"timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E }, {"ignore_io_errors", "Ignore IO errors for stable long-duration runs with network output", OFFSET(ignore_io_errors), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, -- 2.39.2 (Apple Git-143) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH] Use existing function to parse time
--- libavformat/hlsenc.c | 32 +++- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index e1714d4eed..1baefe852f 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -35,6 +35,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" #include "libavutil/log.h" +#include "libavutil/parseutils.h" #include "libavutil/random_seed.h" #include "libavutil/time.h" #include "libavutil/time_internal.h" @@ -1251,27 +1252,6 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, return 0; } -static double parse_iso8601(const char *ptr) { -struct tm program_date_time; -int y,M,d,h,m; -double s; -int num_scanned = sscanf(ptr, "%d-%d-%dT%d:%d:%lf", &y, &M, &d, &h, &m, &s); - -if (num_scanned < 6) { -return -1; -} - -program_date_time.tm_year = y - 1900; -program_date_time.tm_mon = M - 1; -program_date_time.tm_mday = d; -program_date_time.tm_hour = h; -program_date_time.tm_min = m; -program_date_time.tm_sec = 0; -program_date_time.tm_isdst = -1; - -return mktime(&program_date_time) + s; -} - static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs) { HLSContext *hls = s->priv_data; @@ -1281,6 +1261,7 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs char line[MAX_URL_SIZE]; const char *ptr; const char *end; +int64_t parsed_time; double discont_program_date_time = 0; if ((ret = ffio_open_whitelist(&in, url, AVIO_FLAG_READ, @@ -1337,11 +1318,11 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs } } } else if (av_strstart(line, "#EXT-X-PROGRAM-DATE-TIME:", &ptr)) { -discont_program_date_time = parse_iso8601(ptr); -if (discont_program_date_time < 0) { +if (av_parse_time(&parsed_time, ptr, 0)) { ret = AVERROR_INVALIDDATA; goto fail; } +discont_program_date_time = parsed_time / 100.0; } else if (av_strstart(line, "#", NULL)) { continue; } else if (line[0]) { @@ -2933,6 +2914,7 @@ static int hls_init(AVFormatContext *s) int i = 0; int j = 0; HLSContext *hls = s->priv_data; +int64_t parsed_time; const char *pattern; VariantStream *vs = NULL; const char *vtt_pattern = hls->flags & HLS_SINGLE_FILE ? ".vtt" : "%d.vtt"; @@ -2942,11 +2924,11 @@ static int hls_init(AVFormatContext *s) double initial_program_date_time; if (hls->init_program_date_time) { -initial_program_date_time = parse_iso8601(hls->init_program_date_time); -if (initial_program_date_time < 0) { +if (av_parse_time(&parsed_time, hls->init_program_date_time, 0)) { av_log(s, AV_LOG_ERROR, "Invalid init_program_date_time\n"); return AVERROR(EINVAL); } +initial_program_date_time = parsed_time / 100.0; } else { initial_program_date_time = av_gettime() / 100.0; } -- 2.39.2 (Apple Git-143) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH] avformat/hlsenc: Only prevent init_time from being used when splitting by time
--- libavformat/hlsenc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 4ef84c05c1..3548299770 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -3090,7 +3090,7 @@ static int hls_init(AVFormatContext *s) if (hls->flags & HLS_APPEND_LIST) { parse_playlist(s, vs->m3u8_name, vs); vs->discontinuity = 1; -if (hls->init_time > 0) { +if ((hls->flags & HLS_SPLIT_BY_TIME) && (hls->init_time > 0)) { av_log(s, AV_LOG_WARNING, "append_list mode does not support hls_init_time," " hls_init_time value will have no effect\n"); hls->init_time = 0; -- 2.39.2 (Apple Git-143) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".