Signed-off-by: Christian Suloway <csulo...@globaleagleent.com> --- libavformat/hlsenc.c | 87 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 18 deletions(-)
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index e13f438..0a48919 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -33,7 +33,7 @@ #include "internal.h" typedef struct HLSSegment { - char filename[1024]; + char *filename; double duration; /* in seconds */ int64_t pos; int64_t size; @@ -73,14 +73,23 @@ typedef struct HLSContext { HLSSegment *segments; HLSSegment *last_segment; + char *dirname; char *basename; char *baseurl; char *format_options_str; AVDictionary *format_options; + char *segment_filename; + AVIOContext *pb; } HLSContext; +static void hls_free_segment(HLSSegment *en) +{ + av_freep(&en->filename); + av_freep(&en); +} + static int hls_mux_init(AVFormatContext *s) { HLSContext *hls = s->priv_data; @@ -119,7 +128,9 @@ static int hls_append_segment(HLSContext *hls, double duration, int64_t pos, if (!en) return AVERROR(ENOMEM); - av_strlcpy(en->filename, av_basename(hls->avf->filename), sizeof(en->filename)); + en->filename = av_strdup(hls->avf->filename); + if (!en->filename) + return AVERROR(ENOMEM); en->duration = duration; en->pos = pos; @@ -136,7 +147,7 @@ static int hls_append_segment(HLSContext *hls, double duration, int64_t pos, if (hls->max_nb_segments && hls->nb_entries >= hls->max_nb_segments) { en = hls->segments; hls->segments = en->next; - av_free(en); + hls_free_segment(en); } else hls->nb_entries++; @@ -152,7 +163,7 @@ static void hls_free_segments(HLSContext *hls) while(p) { en = p; p = p->next; - av_free(en); + hls_free_segment(en); } } @@ -186,6 +197,7 @@ static int hls_window(AVFormatContext *s, int last) sequence); for (en = hls->segments; en; en = en->next) { + avio_printf(hls->pb, "#EXTINF:%f,\n", en->duration); if (hls->flags & HLS_SINGLE_FILE) avio_printf(hls->pb, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n", @@ -208,6 +220,8 @@ static int hls_start(AVFormatContext *s) HLSContext *c = s->priv_data; AVFormatContext *oc = c->avf; int err = 0; + int filename_size; + char *filename; if (c->flags & HLS_SINGLE_FILE) av_strlcpy(oc->filename, c->basename, @@ -220,8 +234,18 @@ static int hls_start(AVFormatContext *s) } c->number++; - if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE, - &s->interrupt_callback, NULL)) < 0) + filename_size = strlen(c->dirname) + strlen(oc->filename) + 1; + filename = av_malloc(filename_size); + if (!filename) + return AVERROR(ENOMEM); + *filename = '\0'; + av_strlcat(filename, c->dirname, filename_size); + av_strlcat(filename, oc->filename, filename_size); + + err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, + &s->interrupt_callback, NULL); + av_free(filename); + if (err < 0) return err; if (oc->oformat->priv_class && oc->priv_data) @@ -237,15 +261,13 @@ static int hls_write_header(AVFormatContext *s) char *p; const char *pattern = "%d.ts"; AVDictionary *options = NULL; - int basename_size = strlen(s->filename) + strlen(pattern) + 1; + int basename_size; + char *basename; hls->sequence = hls->start_sequence; hls->recording_time = hls->time * AV_TIME_BASE; hls->start_pts = AV_NOPTS_VALUE; - if (hls->flags & HLS_SINGLE_FILE) - pattern = ".ts"; - if (hls->format_options_str) { ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0); if (ret < 0) { @@ -270,21 +292,45 @@ static int hls_write_header(AVFormatContext *s) goto fail; } - hls->basename = av_malloc(basename_size); - - if (!hls->basename) { + hls->dirname = av_strdup(s->filename); + if (!hls->dirname) { ret = AVERROR(ENOMEM); goto fail; } - strcpy(hls->basename, s->filename); + basename = (char *)av_basename(hls->dirname); - p = strrchr(hls->basename, '.'); + if (hls->segment_filename) { + hls->basename = av_strdup(av_basename(hls->segment_filename)); + if (!hls->basename) { + ret = AVERROR(ENOMEM); + goto fail; + } + if (strlen(hls->basename) != strlen(hls->segment_filename)) { + av_log(hls, AV_LOG_ERROR, "invalid segment filename %s\n", + hls->segment_filename); + ret = AVERROR(EINVAL); + goto fail; + } + } else { + if (hls->flags & HLS_SINGLE_FILE) + pattern = ".ts"; - if (p) - *p = '\0'; + basename_size = strlen(basename) + strlen(pattern) + 1; + hls->basename = av_malloc(basename_size); + if (!hls->basename) { + ret = AVERROR(ENOMEM); + goto fail; + } + + av_strlcpy(hls->basename, basename, basename_size); + p = strrchr(hls->basename, '.'); + if (p) + *p = '\0'; + av_strlcat(hls->basename, pattern, basename_size); + } - av_strlcat(hls->basename, pattern, basename_size); + *basename = '\0'; if ((ret = hls_mux_init(s)) < 0) goto fail; @@ -309,6 +355,7 @@ fail: av_dict_free(&options); if (ret) { + av_free(hls->dirname); av_free(hls->basename); if (hls->avf) avformat_free_context(hls->avf); @@ -396,7 +443,10 @@ static int hls_write_trailer(struct AVFormatContext *s) hls_window(s, 1); hls_free_segments(hls); + av_free(hls->dirname); + avio_close(hls->pb); + return 0; } @@ -412,6 +462,7 @@ static const AVOption options[] = { {"hls_base_url", "url to prepend to each playlist entry", OFFSET(baseurl), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, {"hls_flags", "set flags affecting HLS playlist and media file generation", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, "flags"}, {"single_file", "generate a single media file indexed with byte ranges", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SINGLE_FILE }, 0, UINT_MAX, E, "flags"}, + {"hls_segment_filename", "filename template for segment files", OFFSET(segment_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, { NULL }, }; -- 1.9.3 (Apple Git-50) _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel