diff options
| author | Tim Redfern <tim@eclectronics.org> | 2013-12-29 12:19:38 +0000 |
|---|---|---|
| committer | Tim Redfern <tim@eclectronics.org> | 2013-12-29 12:19:38 +0000 |
| commit | f7813a5324be39d13ab536c245d15dfc602a7849 (patch) | |
| tree | fad99148b88823d34a5df2f0a25881a002eb291b /ffmpeg/libavformat/segment.c | |
| parent | b7a5a477b8ff4d4e3028b9dfb9a9df0a41463f92 (diff) | |
basic type mechanism working
Diffstat (limited to 'ffmpeg/libavformat/segment.c')
| -rw-r--r-- | ffmpeg/libavformat/segment.c | 112 |
1 files changed, 64 insertions, 48 deletions
diff --git a/ffmpeg/libavformat/segment.c b/ffmpeg/libavformat/segment.c index dbcfe89..91c1432 100644 --- a/ffmpeg/libavformat/segment.c +++ b/ffmpeg/libavformat/segment.c @@ -1,20 +1,20 @@ /* * Copyright (c) 2011, Luca Barbato * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -43,7 +43,8 @@ typedef struct SegmentListEntry { int index; double start_time, end_time; int64_t start_pts; - char filename[1024]; + int64_t offset_pts; + char *filename; struct SegmentListEntry *next; } SegmentListEntry; @@ -71,6 +72,7 @@ typedef struct { char *list; ///< filename for the segment list file int list_flags; ///< flags affecting list generation int list_size; ///< number of entries for the segment list file + char *list_entry_prefix; ///< prefix to add to list entry filenames ListType list_type; ///< set the list type AVIOContext *list_pb; ///< list file put-byte context char *time_str; ///< segment duration specification string @@ -85,12 +87,12 @@ typedef struct { int nb_frames; ///< number of elments in the frames array int frame_count; - char *time_delta_str; ///< approximation value duration used for the segment times int64_t time_delta; int individual_header_trailer; /**< Set by a private option. */ int write_header_trailer; /**< Set by a private option. */ int reset_timestamps; ///< reset timestamps at the begin of each segment + int64_t initial_offset; ///< initial timestamps offset, expressed in microseconds char *reference_stream_specifier; ///< reference stream specifier int reference_stream_index; @@ -157,6 +159,7 @@ static int set_segment_filename(AVFormatContext *s) { SegmentContext *seg = s->priv_data; AVFormatContext *oc = seg->avf; + size_t size; if (seg->segment_idx_wrap) seg->segment_idx %= seg->segment_idx_wrap; @@ -165,7 +168,19 @@ static int set_segment_filename(AVFormatContext *s) av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", s->filename); return AVERROR(EINVAL); } - av_strlcpy(seg->cur_entry.filename, oc->filename, sizeof(seg->cur_entry.filename)); + + /* copy modified name in list entry */ + size = strlen(av_basename(oc->filename)) + 1; + if (seg->list_entry_prefix) + size += strlen(seg->list_entry_prefix); + + seg->cur_entry.filename = av_mallocz(size); + if (!seg->cur_entry.filename) + return AVERROR(ENOMEM); + snprintf(seg->cur_entry.filename, size, "%s%s", + seg->list_entry_prefix ? seg->list_entry_prefix : "", + av_basename(oc->filename)); + return 0; } @@ -186,11 +201,12 @@ static int segment_start(AVFormatContext *s, int write_header) seg->segment_idx++; if ((err = set_segment_filename(s)) < 0) return err; - seg->segment_count++; if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE, - &s->interrupt_callback, NULL)) < 0) + &s->interrupt_callback, NULL)) < 0) { + av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename); return err; + } if (oc->oformat->priv_class && oc->priv_data) av_opt_set(oc->priv_data, "resend_headers", "1", 0); /* mpegts specific */ @@ -211,8 +227,10 @@ static int segment_list_open(AVFormatContext *s) ret = avio_open2(&seg->list_pb, seg->list, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL); - if (ret < 0) + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Failed to open segment list '%s'\n", seg->list); return ret; + } if (seg->list_type == LIST_TYPE_M3U8 && seg->segment_list_entries) { SegmentListEntry *entry; @@ -303,6 +321,7 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last) if (seg->list_size && seg->segment_count > seg->list_size) { entry = seg->segment_list_entries; seg->segment_list_entries = seg->segment_list_entries->next; + av_free(entry->filename); av_freep(&entry); } @@ -319,6 +338,10 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last) avio_flush(seg->list_pb); } + av_log(s, AV_LOG_VERBOSE, "segment:'%s' count:%d ended\n", + seg->avf->filename, seg->segment_count); + seg->segment_count++; + end: avio_close(oc->pb); @@ -554,15 +577,6 @@ static int seg_write_header(AVFormatContext *s) } } - if (seg->time_delta_str) { - if ((ret = av_parse_time(&seg->time_delta, seg->time_delta_str, 1)) < 0) { - av_log(s, AV_LOG_ERROR, - "Invalid time duration specification '%s' for delta option\n", - seg->time_delta_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; @@ -602,12 +616,13 @@ static int seg_write_header(AVFormatContext *s) if ((ret = set_segment_filename(s)) < 0) goto fail; - seg->segment_count++; if (seg->write_header_trailer) { if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE, - &s->interrupt_callback, NULL)) < 0) + &s->interrupt_callback, NULL)) < 0) { + av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename); goto fail; + } } else { if ((ret = open_null_ctx(&oc->pb)) < 0) goto fail; @@ -644,18 +659,18 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) SegmentContext *seg = s->priv_data; AVFormatContext *oc = seg->avf; AVStream *st = s->streams[pkt->stream_index]; - int64_t end_pts = INT64_MAX; + int64_t end_pts = INT64_MAX, offset; int start_frame = INT_MAX; int ret; if (seg->times) { - end_pts = seg->segment_count <= seg->nb_times ? - seg->times[seg->segment_count-1] : INT64_MAX; + end_pts = seg->segment_count < seg->nb_times ? + seg->times[seg->segment_count] : INT64_MAX; } else if (seg->frames) { start_frame = seg->segment_count <= seg->nb_frames ? - seg->frames[seg->segment_count-1] : INT_MAX; + seg->frames[seg->segment_count] : INT_MAX; } else { - end_pts = seg->time * seg->segment_count; + end_pts = seg->time * (seg->segment_count+1); } av_dlog(s, "packet stream:%d pts:%s pts_time:%s is_key:%d frame:%d\n", @@ -669,12 +684,10 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) (pkt->pts != AV_NOPTS_VALUE && av_compare_ts(pkt->pts, st->time_base, end_pts-seg->time_delta, AV_TIME_BASE_Q) >= 0))) { - ret = segment_end(s, seg->individual_header_trailer, 0); - - if (!ret) - ret = segment_start(s, seg->individual_header_trailer); + if ((ret = segment_end(s, seg->individual_header_trailer, 0)) < 0) + goto fail; - if (ret) + if ((ret = segment_start(s, seg->individual_header_trailer)) < 0) goto fail; oc = seg->avf; @@ -688,29 +701,29 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) } if (seg->is_first_pkt) { - av_log(s, AV_LOG_DEBUG, "segment:'%s' starts with packet stream:%d pts:%s pts_time:%s frame:%d\n", + av_log(s, AV_LOG_VERBOSE, "segment:'%s' starts with packet stream:%d pts:%s pts_time:%s frame:%d\n", seg->avf->filename, pkt->stream_index, av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), seg->frame_count); seg->is_first_pkt = 0; } - if (seg->reset_timestamps) { - av_log(s, AV_LOG_DEBUG, "stream:%d start_pts_time:%s pts:%s pts_time:%s dts:%s dts_time:%s", - pkt->stream_index, - av_ts2timestr(seg->cur_entry.start_pts, &AV_TIME_BASE_Q), - av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), - av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base)); + av_log(s, AV_LOG_DEBUG, "stream:%d start_pts_time:%s pts:%s pts_time:%s dts:%s dts_time:%s", + pkt->stream_index, + av_ts2timestr(seg->cur_entry.start_pts, &AV_TIME_BASE_Q), + av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), + av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base)); - /* compute new timestamps */ - if (pkt->pts != AV_NOPTS_VALUE) - pkt->pts -= av_rescale_q(seg->cur_entry.start_pts, AV_TIME_BASE_Q, st->time_base); - if (pkt->dts != AV_NOPTS_VALUE) - pkt->dts -= av_rescale_q(seg->cur_entry.start_pts, AV_TIME_BASE_Q, st->time_base); + /* compute new timestamps */ + offset = av_rescale_q(seg->initial_offset - (seg->reset_timestamps ? seg->cur_entry.start_pts : 0), + AV_TIME_BASE_Q, st->time_base); + if (pkt->pts != AV_NOPTS_VALUE) + pkt->pts += offset; + if (pkt->dts != AV_NOPTS_VALUE) + pkt->dts += offset; - av_log(s, AV_LOG_DEBUG, " -> pts:%s pts_time:%s dts:%s dts_time:%s\n", - av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), - av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base)); - } + av_log(s, AV_LOG_DEBUG, " -> pts:%s pts_time:%s dts:%s dts_time:%s\n", + 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(oc, pkt->stream_index, pkt, s); @@ -754,6 +767,7 @@ fail: cur = seg->segment_list_entries; while (cur) { next = cur->next; + av_free(cur->filename); av_free(cur); cur = next; } @@ -774,6 +788,7 @@ static const AVOption options[] = { { "live", "enable live-friendly list generation (useful for HLS)", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_LIST_FLAG_LIVE }, INT_MIN, INT_MAX, E, "list_flags"}, { "segment_list_size", "set the maximum number of playlist entries", OFFSET(list_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, + { "segment_list_entry_prefix", "set prefix to prepend to each list entry filename", OFFSET(list_entry_prefix), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, { "segment_list_type", "set the segment list type", OFFSET(list_type), AV_OPT_TYPE_INT, {.i64 = LIST_TYPE_UNDEFINED}, -1, LIST_TYPE_NB-1, E, "list_type" }, { "flat", "flat format", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_FLAT }, INT_MIN, INT_MAX, E, "list_type" }, @@ -784,7 +799,7 @@ static const AVOption options[] = { { "hls", "Apple HTTP Live Streaming compatible", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_M3U8 }, INT_MIN, INT_MAX, E, "list_type" }, { "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_str), AV_OPT_TYPE_STRING, {.str = "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, 0, 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 }, @@ -793,6 +808,7 @@ static const AVOption options[] = { { "individual_header_trailer", "write header/trailer to each segment", OFFSET(individual_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E }, { "write_header_trailer", "write a header to the first segment and a trailer to the last one", OFFSET(write_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E }, { "reset_timestamps", "reset timestamps at the begin of each segment", OFFSET(reset_timestamps), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E }, + { "initial_offset", "set initial timestamp offset", OFFSET(initial_offset), AV_OPT_TYPE_DURATION, {.i64 = 0}, -INT64_MAX, INT64_MAX, E }, { NULL }, }; |
