X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fsegment.c;h=f67456fa571d7799e06285325d9b7a7b2cb0ccc4;hb=4147f63d63358e5c1969bfe431ee08ca54f8434d;hp=7fb4dc7d2124c72d8abeaafff88d2370c877e1e9;hpb=1f1ec958f6c68a5ceafea206a99c895f62d0f3ec;p=ffmpeg diff --git a/libavformat/segment.c b/libavformat/segment.c index 7fb4dc7d212..f67456fa571 100644 --- a/libavformat/segment.c +++ b/libavformat/segment.c @@ -72,10 +72,9 @@ typedef struct SegmentContext { int segment_idx_wrap; ///< number after which the index wraps int segment_idx_wrap_nb; ///< number of time the index has wraped int segment_count; ///< number of segment files already written - AVOutputFormat *oformat; + ff_const59 AVOutputFormat *oformat; AVFormatContext *avf; char *format; ///< format to use for output segment files - char *format_options_str; ///< format options to use for output segment files AVDictionary *format_options; char *list; ///< filename for the segment list file int list_flags; ///< flags affecting list generation @@ -163,12 +162,11 @@ static int segment_mux_init(AVFormatContext *s) oc->flags = s->flags; for (i = 0; i < s->nb_streams; i++) { - AVStream *st; - AVCodecParameters *ipar, *opar; + AVStream *st, *ist = s->streams[i]; + AVCodecParameters *ipar = ist->codecpar, *opar; if (!(st = avformat_new_stream(oc, NULL))) return AVERROR(ENOMEM); - ipar = s->streams[i]->codecpar; opar = st->codecpar; avcodec_parameters_copy(opar, ipar); if (!oc->oformat->codec_tag || @@ -178,9 +176,17 @@ static int segment_mux_init(AVFormatContext *s) } else { opar->codec_tag = 0; } - st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio; - st->time_base = s->streams[i]->time_base; - av_dict_copy(&st->metadata, s->streams[i]->metadata, 0); + st->sample_aspect_ratio = ist->sample_aspect_ratio; + st->time_base = ist->time_base; + st->avg_frame_rate = ist->avg_frame_rate; + st->disposition = ist->disposition; +#if FF_API_LAVF_AVCTX +FF_DISABLE_DEPRECATION_WARNINGS + if (ipar->codec_tag == MKTAG('t','m','c','d')) + st->codec->time_base = ist->codec->time_base; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + av_dict_copy(&st->metadata, ist->metadata, 0); } return 0; @@ -421,7 +427,7 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last) rate = s->streams[i]->avg_frame_rate;/* Get fps from the video stream */ err = av_timecode_init_from_string(&tc, rate, tcr->value, s); if (err < 0) { - av_log(s, AV_LOG_WARNING, "Could not increment timecode, error occurred during timecode creation."); + av_log(s, AV_LOG_WARNING, "Could not increment global timecode, error occurred during timecode creation.\n"); break; } tc.start += (int)((seg->cur_entry.end_time - seg->cur_entry.start_time) * av_q2d(rate));/* increment timecode */ @@ -431,7 +437,23 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last) } } } else { - av_log(s, AV_LOG_WARNING, "Could not increment timecode, no timecode metadata found"); + av_log(s, AV_LOG_WARNING, "Could not increment global timecode, no global timecode metadata found.\n"); + } + for (i = 0; i < s->nb_streams; i++) { + if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + char st_buf[AV_TIMECODE_STR_SIZE]; + AVTimecode st_tc; + AVRational st_rate = s->streams[i]->avg_frame_rate; + AVDictionaryEntry *st_tcr = av_dict_get(s->streams[i]->metadata, "timecode", NULL, 0); + if (st_tcr) { + if ((av_timecode_init_from_string(&st_tc, st_rate, st_tcr->value, s) < 0)) { + av_log(s, AV_LOG_WARNING, "Could not increment stream %d timecode, error occurred during timecode creation.\n", i); + continue; + } + st_tc.start += (int)((seg->cur_entry.end_time - seg->cur_entry.start_time) * av_q2d(st_rate)); // increment timecode + av_dict_set(&s->streams[i]->metadata, "timecode", av_timecode_make_string(&st_tc, st_buf, 0), 0); + } + } } } @@ -697,15 +719,6 @@ static int seg_init(AVFormatContext *s) } } - if (seg->format_options_str) { - ret = av_dict_parse_string(&seg->format_options, seg->format_options_str, "=", ":", 0); - if (ret < 0) { - av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n", - seg->format_options_str); - return ret; - } - } - if (seg->list) { if (seg->list_type == LIST_TYPE_UNDEFINED) { if (av_match_ext(seg->list, "csv" )) seg->list_type = LIST_TYPE_CSV; @@ -768,7 +781,7 @@ static int seg_init(AVFormatContext *s) ret = avformat_init_output(oc, &options); if (av_dict_count(options)) { av_log(s, AV_LOG_ERROR, - "Some of the provided format options in '%s' are not recognized\n", seg->format_options_str); + "Some of the provided format options are not recognized\n"); av_dict_free(&options); return AVERROR(EINVAL); } @@ -859,6 +872,19 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) if (!seg->avf || !seg->avf->pb) return AVERROR(EINVAL); + if (!st->codecpar->extradata_size) { + int pkt_extradata_size; + uint8_t *pkt_extradata = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &pkt_extradata_size); + if (pkt_extradata && pkt_extradata_size > 0) { + ret = ff_alloc_extradata(st->codecpar, pkt_extradata_size); + if (ret < 0) { + av_log(s, AV_LOG_WARNING, "Unable to add extradata to stream. Output segments may be invalid.\n"); + goto calc_times; + } + memcpy(st->codecpar->extradata, pkt_extradata, pkt_extradata_size); + } + } + calc_times: if (seg->times) { end_pts = seg->segment_count < seg->nb_times ? @@ -945,7 +971,8 @@ calc_times: av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base)); - ret = ff_write_chained(seg->avf, pkt->stream_index, pkt, s, seg->initial_offset || seg->reset_timestamps); + ret = ff_write_chained(seg->avf, pkt->stream_index, pkt, s, + seg->initial_offset || seg->reset_timestamps || seg->avf->oformat->interleave_packet); fail: if (pkt->stream_index == seg->reference_stream_index) { @@ -980,7 +1007,6 @@ fail: if (seg->list) ff_format_io_close(s, &seg->list_pb); - av_dict_free(&seg->format_options); av_opt_free(seg); av_freep(&seg->times); av_freep(&seg->frames); @@ -1008,10 +1034,8 @@ static int seg_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt) if (ret == 1) { AVStream *st = s->streams[pkt->stream_index]; AVStream *ost = oc->streams[pkt->stream_index]; - st->internal->bsfcs = ost->internal->bsfcs; - st->internal->nb_bsfcs = ost->internal->nb_bsfcs; - ost->internal->bsfcs = NULL; - ost->internal->nb_bsfcs = 0; + st->internal->bsfc = ost->internal->bsfc; + ost->internal->bsfc = NULL; } return ret; } @@ -1021,9 +1045,9 @@ static int seg_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt) #define OFFSET(x) offsetof(SegmentContext, x) #define E AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "reference_stream", "set reference stream", OFFSET(reference_stream_specifier), AV_OPT_TYPE_STRING, {.str = "auto"}, CHAR_MIN, CHAR_MAX, E }, + { "reference_stream", "set reference stream", OFFSET(reference_stream_specifier), AV_OPT_TYPE_STRING, {.str = "auto"}, 0, 0, E }, { "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_format_options", "set list of options for the container format used for the segments", OFFSET(format_options), AV_OPT_TYPE_DICT, {.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 }, @@ -1045,7 +1069,7 @@ static const AVOption options[] = { { "segment_clocktime_offset", "set segment clocktime offset", OFFSET(clocktime_offset), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, 86400000000LL, E}, { "segment_clocktime_wrap_duration", "set segment clocktime wrapping duration", OFFSET(clocktime_wrap_duration), AV_OPT_TYPE_DURATION, {.i64 = INT64_MAX}, 0, INT64_MAX, E}, { "segment_time", "set segment duration", OFFSET(time_str),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, - { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, 0, E }, + { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, INT64_MAX, E }, { "segment_times", "set segment split time points", OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E }, { "segment_frames", "set segment split frame numbers", OFFSET(frames_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E }, { "segment_wrap", "set number after which the index wraps", OFFSET(segment_idx_wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },