35
34
const AVClass *class; /**< Class for private options. */
36
AVOutputFormat *oformat;
37
37
AVFormatContext *avf;
38
38
char *format; /**< Set by a private option. */
39
39
char *list; /**< Set by a private option. */
40
int list_type; /**< Set by a private option. */
40
41
float time; /**< Set by a private option. */
41
42
int size; /**< Set by a private option. */
43
int wrap; /**< Set by a private option. */
44
int individual_header_trailer; /**< Set by a private option. */
45
int write_header_trailer; /**< Set by a private option. */
42
46
int64_t offset_time;
43
47
int64_t recording_time;
48
static int segment_start(AVFormatContext *s)
57
static int segment_mux_init(AVFormatContext *s)
59
SegmentContext *seg = s->priv_data;
63
seg->avf = oc = avformat_alloc_context();
65
return AVERROR(ENOMEM);
67
oc->oformat = seg->oformat;
68
oc->interrupt_callback = s->interrupt_callback;
70
for (i = 0; i < s->nb_streams; i++) {
72
if (!(st = avformat_new_stream(oc, NULL)))
73
return AVERROR(ENOMEM);
74
avcodec_copy_context(st->codec, s->streams[i]->codec);
75
st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio;
81
static int segment_hls_window(AVFormatContext *s, int last)
83
SegmentContext *seg = s->priv_data;
87
if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE,
88
&s->interrupt_callback, NULL)) < 0)
91
avio_printf(seg->pb, "#EXTM3U\n");
92
avio_printf(seg->pb, "#EXT-X-VERSION:3\n");
93
avio_printf(seg->pb, "#EXT-X-TARGETDURATION:%d\n", (int)seg->time);
94
avio_printf(seg->pb, "#EXT-X-MEDIA-SEQUENCE:%d\n",
95
FFMAX(0, seg->number - seg->size));
97
for (i = FFMAX(0, seg->number - seg->size);
98
i < seg->number; i++) {
99
avio_printf(seg->pb, "#EXTINF:%d,\n", (int)seg->time);
100
av_get_frame_filename(buf, sizeof(buf), s->filename, i);
101
avio_printf(seg->pb, "%s\n", buf);
105
avio_printf(seg->pb, "#EXT-X-ENDLIST\n");
107
avio_closep(&seg->pb);
111
static int segment_start(AVFormatContext *s, int write_header)
50
113
SegmentContext *c = s->priv_data;
51
114
AVFormatContext *oc = c->avf;
118
avformat_free_context(oc);
120
if ((err = segment_mux_init(s)) < 0)
126
c->number %= c->wrap;
54
128
if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
55
129
s->filename, c->number++) < 0)
56
130
return AVERROR(EINVAL);
59
133
&s->interrupt_callback, NULL)) < 0)
62
if (!oc->priv_data && oc->oformat->priv_data_size > 0) {
63
oc->priv_data = av_mallocz(oc->oformat->priv_data_size);
66
return AVERROR(ENOMEM);
68
if (oc->oformat->priv_class) {
69
*(const AVClass**)oc->priv_data = oc->oformat->priv_class;
70
av_opt_set_defaults(oc->priv_data);
136
if (oc->oformat->priv_class && oc->priv_data)
137
av_opt_set(oc->priv_data, "resend_headers", "1", 0); /* mpegts specific */
74
if ((err = oc->oformat->write_header(oc)) < 0) {
140
if ((err = avformat_write_header(oc, NULL)) < 0)
82
av_freep(&oc->priv_data);
87
static int segment_end(AVFormatContext *oc)
147
static int segment_end(AVFormatContext *oc, int write_trailer)
91
if (oc->oformat->write_trailer)
92
ret = oc->oformat->write_trailer(oc);
151
av_write_frame(oc, NULL); /* Flush any buffered data (fragmented mp4) */
153
av_write_trailer(oc);
94
154
avio_close(oc->pb);
95
if (oc->oformat->priv_class)
96
av_opt_free(oc->priv_data);
97
av_freep(&oc->priv_data);
159
static int open_null_ctx(AVIOContext **ctx)
161
int buf_size = 32768;
162
uint8_t *buf = av_malloc(buf_size);
164
return AVERROR(ENOMEM);
165
*ctx = avio_alloc_context(buf, buf_size, AVIO_FLAG_WRITE, NULL, NULL, NULL, NULL);
168
return AVERROR(ENOMEM);
173
static void close_null_ctx(AVIOContext *pb)
102
179
static int seg_write_header(AVFormatContext *s)
104
181
SegmentContext *seg = s->priv_data;
182
AVFormatContext *oc = NULL;
109
186
seg->offset_time = 0;
110
187
seg->recording_time = seg->time * 1000000;
188
if (!seg->write_header_trailer)
189
seg->individual_header_trailer = 0;
191
if (seg->list && seg->list_type != LIST_HLS)
113
192
if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE,
114
193
&s->interrupt_callback, NULL)) < 0)
117
for (i = 0; i< s->nb_streams; i++)
196
for (i = 0; i < s->nb_streams; i++)
118
197
seg->has_video +=
119
198
(s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO);
123
202
"More than a single video stream present, "
124
203
"expect issues decoding it.\n");
126
oc = avformat_alloc_context();
129
ret = AVERROR(ENOMEM);
133
oc->oformat = av_guess_format(seg->format, s->filename, NULL);
205
seg->oformat = av_guess_format(seg->format, s->filename, NULL);
136
208
ret = AVERROR_MUXER_NOT_FOUND;
139
if (oc->oformat->flags & AVFMT_NOFILE) {
211
if (seg->oformat->flags & AVFMT_NOFILE) {
140
212
av_log(s, AV_LOG_ERROR, "format %s not supported.\n",
142
214
ret = AVERROR(EINVAL);
148
oc->streams = s->streams;
149
oc->nb_streams = s->nb_streams;
218
if ((ret = segment_mux_init(s)) < 0)
151
222
if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
152
223
s->filename, seg->number++) < 0) {
157
if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
158
&s->interrupt_callback, NULL)) < 0)
228
if (seg->write_header_trailer) {
229
if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
230
&s->interrupt_callback, NULL)) < 0)
233
if ((ret = open_null_ctx(&oc->pb)) < 0)
161
237
if ((ret = avformat_write_header(oc, NULL)) < 0) {
162
238
avio_close(oc->pb);
242
if (!seg->write_header_trailer) {
243
close_null_ctx(oc->pb);
244
if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
245
&s->interrupt_callback, NULL)) < 0)
167
avio_printf(seg->pb, "%s\n", oc->filename);
250
if (seg->list_type == LIST_HLS) {
251
if ((ret = segment_hls_window(s, 0)) < 0)
254
avio_printf(seg->pb, "%s\n", oc->filename);
176
262
avio_close(seg->pb);
177
avformat_free_context(oc);
264
avformat_free_context(seg->avf);
184
271
SegmentContext *seg = s->priv_data;
185
272
AVFormatContext *oc = seg->avf;
186
AVStream *st = oc->streams[pkt->stream_index];
273
AVStream *st = s->streams[pkt->stream_index];
187
274
int64_t end_pts = seg->recording_time * seg->number;
190
if ((seg->has_video && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) &&
191
av_compare_ts(pkt->pts, st->time_base,
192
end_pts, AV_TIME_BASE_Q) >= 0 &&
193
pkt->flags & AV_PKT_FLAG_KEY) {
275
int ret, can_split = 1;
277
if (seg->has_video) {
278
can_split = st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
279
pkt->flags & AV_PKT_FLAG_KEY;
282
if (can_split && av_compare_ts(pkt->pts, st->time_base, end_pts,
283
AV_TIME_BASE_Q) >= 0) {
195
284
av_log(s, AV_LOG_DEBUG, "Next segment starts at %d %"PRId64"\n",
196
285
pkt->stream_index, pkt->pts);
198
ret = segment_end(oc);
287
ret = segment_end(oc, seg->individual_header_trailer);
201
ret = segment_start(s);
290
ret = segment_start(s, seg->individual_header_trailer);
207
avio_printf(seg->pb, "%s\n", oc->filename);
209
if (!(seg->number % seg->size)) {
211
if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE,
212
&s->interrupt_callback, NULL)) < 0)
298
if (seg->list_type == LIST_HLS) {
299
if ((ret = segment_hls_window(s, 0)) < 0)
302
avio_printf(seg->pb, "%s\n", oc->filename);
304
if (seg->size && !(seg->number % seg->size)) {
305
avio_closep(&seg->pb);
306
if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE,
307
&s->interrupt_callback, NULL)) < 0)
219
ret = oc->oformat->write_packet(oc, pkt);
314
ret = ff_write_chained(oc, pkt->stream_index, pkt, s);
226
319
avio_close(seg->pb);
227
320
avformat_free_context(oc);
235
328
SegmentContext *seg = s->priv_data;
236
329
AVFormatContext *oc = seg->avf;
237
int ret = segment_end(oc);
331
if (!seg->write_header_trailer) {
332
if ((ret = segment_end(oc, 0)) < 0)
334
open_null_ctx(&oc->pb);
335
ret = av_write_trailer(oc);
336
close_null_ctx(oc->pb);
338
ret = segment_end(oc, 1);
344
if (seg->list && seg->list_type == LIST_HLS) {
345
if ((ret = segment_hls_window(s, 1) < 0))
242
351
avformat_free_context(oc);
249
358
{ "segment_format", "container format used for the segments", OFFSET(format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
250
359
{ "segment_time", "segment length in seconds", OFFSET(time), AV_OPT_TYPE_FLOAT, {.dbl = 2}, 0, FLT_MAX, E },
251
360
{ "segment_list", "output the segment list", OFFSET(list), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
252
{ "segment_list_size", "maximum number of playlist entries", OFFSET(size), AV_OPT_TYPE_INT, {.dbl = 5}, 0, INT_MAX, E },
361
{ "segment_list_size", "maximum number of playlist entries", OFFSET(size), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E },
362
{ "segment_list_type", "segment list format", OFFSET(list_type), AV_OPT_TYPE_INT, {.i64 = LIST_FLAT}, 0, 2, E, "list_type" },
363
{ "flat", "plain list (default)", 0, AV_OPT_TYPE_CONST, {.i64 = LIST_FLAT}, 0, 0, E, "list_type" },
364
{ "hls", "Apple HTTP Live Streaming compatible", 0, AV_OPT_TYPE_CONST, {.i64 = LIST_HLS}, 0, 0, E, "list_type" },
365
{ "segment_wrap", "number after which the index wraps", OFFSET(wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
366
{ "individual_header_trailer", "write header/trailer to each segment", OFFSET(individual_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
367
{ "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 },
264
379
AVOutputFormat ff_segment_muxer = {
265
380
.name = "segment",
266
.long_name = NULL_IF_CONFIG_SMALL("segment muxer"),
381
.long_name = NULL_IF_CONFIG_SMALL("segment"),
267
382
.priv_data_size = sizeof(SegmentContext),
268
.flags = AVFMT_GLOBALHEADER | AVFMT_NOFILE,
383
.flags = AVFMT_NOFILE,
269
384
.write_header = seg_write_header,
270
385
.write_packet = seg_write_packet,
271
386
.write_trailer = seg_write_trailer,