summaryrefslogtreecommitdiff
path: root/ffmpeg/libavformat/segment.c
diff options
context:
space:
mode:
Diffstat (limited to 'ffmpeg/libavformat/segment.c')
-rw-r--r--ffmpeg/libavformat/segment.c112
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 },
};