X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fsegment.c;h=69038ca3dd93cdc09928f2186e2c2698f003a354;hb=235863463abcfda0e428bf1a79009316b2dd7895;hp=b65a2ebdba90a4d8fec5fc451eb0786f7d1c0829;hpb=72bec029ee18aada1c54101f4fa0aa991355321c;p=ffmpeg diff --git a/libavformat/segment.c b/libavformat/segment.c index b65a2ebdba9..69038ca3dd9 100644 --- a/libavformat/segment.c +++ b/libavformat/segment.c @@ -105,6 +105,7 @@ typedef struct SegmentContext { int64_t time_delta; int individual_header_trailer; /**< Set by a private option. */ int write_header_trailer; /**< Set by a private option. */ + char *header_filename; ///< filename to write the output header to int reset_timestamps; ///< reset timestamps at the begin of each segment int64_t initial_offset; ///< initial timestamps offset, expressed in microseconds @@ -225,7 +226,7 @@ static int segment_start(AVFormatContext *s, int write_header) } seg->segment_idx++; - if ((seg->segment_idx_wrap) && (seg->segment_idx%seg->segment_idx_wrap == 0)) + if ((seg->segment_idx_wrap) && (seg->segment_idx % seg->segment_idx_wrap == 0)) seg->segment_idx_wrap_nb++; if ((err = set_segment_filename(s)) < 0) @@ -236,6 +237,8 @@ static int segment_start(AVFormatContext *s, int write_header) av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename); return err; } + if (!seg->individual_header_trailer) + oc->pb->seekable = 0; if (oc->oformat->priv_class && oc->priv_data) av_opt_set(oc->priv_data, "mpegts_flags", "+resend_headers", 0); @@ -357,17 +360,17 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last) av_freep(&entry); } - avio_closep(&seg->list_pb); if ((ret = segment_list_open(s)) < 0) goto end; for (entry = seg->segment_list_entries; entry; entry = entry->next) segment_list_print_entry(seg->list_pb, seg->list_type, entry, s); if (seg->list_type == LIST_TYPE_M3U8 && is_last) avio_printf(seg->list_pb, "#EXT-X-ENDLIST\n"); + avio_closep(&seg->list_pb); } else { segment_list_print_entry(seg->list_pb, seg->list_type, &seg->cur_entry, s); + avio_flush(seg->list_pb); } - avio_flush(seg->list_pb); } av_log(s, AV_LOG_VERBOSE, "segment:'%s' count:%d ended\n", @@ -593,6 +596,11 @@ static int seg_write_header(AVFormatContext *s) if (!seg->write_header_trailer) seg->individual_header_trailer = 0; + if (seg->header_filename) { + seg->write_header_trailer = 1; + seg->individual_header_trailer = 0; + } + if (!!seg->time_str + !!seg->times_str + !!seg->frames_str > 1) { av_log(s, AV_LOG_ERROR, "segment_time, segment_times, and segment_frames options " @@ -635,8 +643,9 @@ static int seg_write_header(AVFormatContext *s) else if (av_match_ext(seg->list, "ffcat,ffconcat")) seg->list_type = LIST_TYPE_FFCONCAT; else seg->list_type = LIST_TYPE_FLAT; } - if ((ret = segment_list_open(s)) < 0) - goto fail; + if (!seg->list_size && seg->list_type != LIST_TYPE_M3U8) + if ((ret = segment_list_open(s)) < 0) + goto fail; } if (seg->list_type == LIST_TYPE_EXT) av_log(s, AV_LOG_WARNING, "'ext' list type option is deprecated in favor of 'csv'\n"); @@ -668,11 +677,13 @@ static int seg_write_header(AVFormatContext *s) goto fail; if (seg->write_header_trailer) { - if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE, + if ((ret = avio_open2(&oc->pb, seg->header_filename ? seg->header_filename : oc->filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL)) < 0) { av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename); goto fail; } + if (!seg->individual_header_trailer) + oc->pb->seekable = 0; } else { if ((ret = open_null_ctx(&oc->pb)) < 0) goto fail; @@ -703,11 +714,18 @@ static int seg_write_header(AVFormatContext *s) if (oc->avoid_negative_ts > 0 && s->avoid_negative_ts < 0) s->avoid_negative_ts = 1; - if (!seg->write_header_trailer) { - close_null_ctxp(&oc->pb); + if (!seg->write_header_trailer || seg->header_filename) { + if (seg->header_filename) { + av_write_frame(oc, NULL); + avio_closep(&oc->pb); + } else { + close_null_ctxp(&oc->pb); + } if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL)) < 0) goto fail; + if (!seg->individual_header_trailer) + oc->pb->seekable = 0; } fail: @@ -743,7 +761,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) int64_t avgt = av_gettime(); time_t sec = avgt / 1000000; localtime_r(&sec, &ti); - usecs = (int64_t)(ti.tm_hour*3600 + ti.tm_min*60 + ti.tm_sec) * 1000000 + (avgt % 1000000); + usecs = (int64_t)(ti.tm_hour * 3600 + ti.tm_min * 60 + ti.tm_sec) * 1000000 + (avgt % 1000000); wrapped_val = usecs % seg->time; if (seg->last_cut != usecs && wrapped_val < seg->last_val) { seg->cut_pending = 1; @@ -751,7 +769,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) } seg->last_val = wrapped_val; } else { - end_pts = seg->time * (seg->segment_count+1); + end_pts = seg->time * (seg->segment_count + 1); } } @@ -779,7 +797,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) goto fail; seg->cut_pending = 0; - seg->cur_entry.index = seg->segment_idx + seg->segment_idx_wrap*seg->segment_idx_wrap_nb; + seg->cur_entry.index = seg->segment_idx + seg->segment_idx_wrap * seg->segment_idx_wrap_nb; seg->cur_entry.start_time = (double)pkt->pts * av_q2d(st->time_base); seg->cur_entry.start_pts = av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q); seg->cur_entry.end_time = seg->cur_entry.start_time + @@ -876,6 +894,7 @@ static const AVOption options[] = { { "segment_format", "set container format used for the segments", OFFSET(format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, { "segment_format_options", "set list of options for the container format used for the segments", OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, { "segment_list", "set the segment list filename", OFFSET(list), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, + { "segment_header_filename", "write a single file containing the header", OFFSET(header_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, { "segment_list_flags","set flags affecting segment list generation", OFFSET(list_flags), AV_OPT_TYPE_FLAGS, {.i64 = SEGMENT_LIST_FLAG_CACHE }, 0, UINT_MAX, E, "list_flags"}, { "cache", "allow list caching", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_LIST_FLAG_CACHE }, INT_MIN, INT_MAX, E, "list_flags"},