]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/dashenc.c
avformat/dashenc: replacing 'min_seg_duration' with 'seg_duration'
[ffmpeg] / libavformat / dashenc.c
index d6474f3549fbd33d8f36f61c6472a1c6f4144398..7169e1101df16aa90303df2989e8da9f2af2c12f 100644 (file)
@@ -94,7 +94,10 @@ typedef struct DASHContext {
     int nb_as;
     int window_size;
     int extra_window_size;
+#if FF_API_DASH_MIN_SEG_DURATION
     int min_seg_duration;
+#endif
+    int64_t seg_duration;
     int remove_at_exit;
     int use_template;
     int use_timeline;
@@ -109,6 +112,7 @@ typedef struct DASHContext {
     const char *init_seg_name;
     const char *media_seg_name;
     const char *utc_timing_url;
+    const char *method;
     const char *user_agent;
     int hls_playlist;
     int http_persistent;
@@ -116,6 +120,7 @@ typedef struct DASHContext {
     AVIOContext *mpd_out;
     AVIOContext *m3u8_out;
     int streaming;
+    int64_t timeout;
 } DASHContext;
 
 static struct codec_string {
@@ -262,10 +267,14 @@ static int flush_dynbuf(OutputStream *os, int *range_length)
 
 static void set_http_options(AVDictionary **options, DASHContext *c)
 {
+    if (c->method)
+        av_dict_set(options, "method", c->method, 0);
     if (c->user_agent)
         av_dict_set(options, "user_agent", c->user_agent, 0);
     if (c->http_persistent)
         av_dict_set_int(options, "multiple_requests", 1, 0);
+    if (c->timeout >= 0)
+        av_dict_set_int(options, "timeout", c->timeout, 0);
 }
 
 static void get_hls_playlist_name(char *playlist_name, int string_size,
@@ -865,6 +874,13 @@ static int dash_init(AVFormatContext *s)
     if (c->single_file)
         c->use_template = 0;
 
+#if FF_API_DASH_MIN_SEG_DURATION
+    if (c->min_seg_duration != 5000000) {
+        av_log(s, AV_LOG_WARNING, "The min_seg_duration option is deprecated and will be removed. Please use the -seg_duration\n");
+        c->seg_duration = c->min_seg_duration;
+    }
+#endif
+
     av_strlcpy(c->dirname, s->url, sizeof(c->dirname));
     ptr = strrchr(c->dirname, '/');
     if (ptr) {
@@ -968,7 +984,7 @@ static int dash_init(AVFormatContext *s)
             else
                 av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
         } else {
-            av_dict_set_int(&opts, "cluster_time_limit", c->min_seg_duration / 1000, 0);
+            av_dict_set_int(&opts, "cluster_time_limit", c->seg_duration / 1000, 0);
             av_dict_set_int(&opts, "cluster_size_limit", 5 * 1024 * 1024, 0); // set a large cluster size limit
             av_dict_set_int(&opts, "dash", 1, 0);
             av_dict_set_int(&opts, "dash_track_number", i + 1, 0);
@@ -1014,8 +1030,8 @@ static int dash_init(AVFormatContext *s)
         os->segment_index = 1;
     }
 
-    if (!c->has_video && c->min_seg_duration <= 0) {
-        av_log(s, AV_LOG_WARNING, "no video stream and no min seg duration set\n");
+    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);
     }
     return 0;
@@ -1027,10 +1043,8 @@ static int dash_write_header(AVFormatContext *s)
     int i, ret;
     for (i = 0; i < s->nb_streams; i++) {
         OutputStream *os = &c->streams[i];
-        if ((ret = avformat_write_header(os->ctx, NULL)) < 0) {
-            dash_free(s);
+        if ((ret = avformat_write_header(os->ctx, NULL)) < 0)
             return ret;
-        }
     }
     ret = write_manifest(s, 0);
     if (!ret)
@@ -1128,6 +1142,28 @@ static int update_stream_extradata(AVFormatContext *s, OutputStream *os,
     return 0;
 }
 
+static void dashenc_delete_file(AVFormatContext *s, char *filename) {
+    DASHContext *c = s->priv_data;
+    int http_base_proto = ff_is_http_proto(filename);
+
+    if (http_base_proto) {
+        AVIOContext *out = NULL;
+        AVDictionary *http_opts = NULL;
+
+        set_http_options(&http_opts, c);
+        av_dict_set(&http_opts, "method", "DELETE", 0);
+
+        if (dashenc_io_open(s, &out, filename, &http_opts) < 0) {
+            av_log(s, AV_LOG_ERROR, "failed to delete %s\n", filename);
+        }
+
+        av_dict_free(&http_opts);
+        dashenc_io_close(s, &out, filename);
+    } else if (unlink(filename) < 0) {
+        av_log(s, AV_LOG_ERROR, "failed to delete %s: %s\n", filename, strerror(errno));
+    }
+}
+
 static int dash_flush(AVFormatContext *s, int final, int stream)
 {
     DASHContext *c = s->priv_data;
@@ -1212,7 +1248,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream)
                 for (j = 0; j < remove; j++) {
                     char filename[1024];
                     snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->segments[j]->file);
-                    unlink(filename);
+                    dashenc_delete_file(s, filename);
                     av_free(os->segments[j]);
                 }
                 os->nb_segments -= remove;
@@ -1261,7 +1297,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
     if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
         pkt->flags & AV_PKT_FLAG_KEY && os->packets_written &&
         av_compare_ts(pkt->pts - os->start_pts, st->time_base,
-                      c->min_seg_duration, AV_TIME_BASE_Q) >= 0) {
+                      c->seg_duration, AV_TIME_BASE_Q) >= 0) {
         int64_t prev_duration = c->last_duration;
 
         c->last_duration = av_rescale_q(pkt->pts - os->start_pts,
@@ -1305,9 +1341,9 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
         flush_init_segment(s, os);
 
     //open the output context when the first frame of a segment is ready
-    if (!c->single_file && !os->out) {
+    if (!c->single_file && os->packets_written == 1) {
         AVDictionary *opts = NULL;
-        const char *proto = avio_find_protocol_name(s->filename);
+        const char *proto = avio_find_protocol_name(s->url);
         int use_rename = proto && !strcmp(proto, "file");
         os->filename[0] = os->full_path[0] = os->temp_path[0] = '\0';
         ff_dash_fill_tmpl_params(os->filename, sizeof(os->filename),
@@ -1364,9 +1400,9 @@ static int dash_write_trailer(AVFormatContext *s)
         for (i = 0; i < s->nb_streams; i++) {
             OutputStream *os = &c->streams[i];
             snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile);
-            unlink(filename);
+            dashenc_delete_file(s, filename);
         }
-        unlink(s->url);
+        dashenc_delete_file(s, s->url);
     }
 
     return 0;
@@ -1401,7 +1437,10 @@ 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 },
     { "window_size", "number of segments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E },
     { "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 },
-    { "min_seg_duration", "minimum segment duration (in microseconds)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 5000000 }, 0, INT_MAX, E },
+#if FF_API_DASH_MIN_SEG_DURATION
+    { "min_seg_duration", "minimum segment duration (in microseconds) (will be deprecated)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 5000000 }, 0, INT_MAX, E },
+#endif
+    { "seg_duration", "segment duration (in seconds, fractional value can be set)", OFFSET(seg_duration), AV_OPT_TYPE_DURATION, { .i64 = 5000000 }, 0, INT_MAX, E },
     { "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, 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 },
@@ -1410,10 +1449,12 @@ static const AVOption options[] = {
     { "init_seg_name", "DASH-templated name to used for the initialization segment", OFFSET(init_seg_name), AV_OPT_TYPE_STRING, {.str = "init-stream$RepresentationID$.m4s"}, 0, 0, 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$.m4s"}, 0, 0, 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 },
+    { "method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
     { "http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
     { "http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
     { "hls_playlist", "Generate HLS playlist files(master.m3u8, media_%d.m3u8)", OFFSET(hls_playlist), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, 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 },
+    { "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E },
     { NULL },
 };