]> git.sesse.net Git - ffmpeg/blob - libavformat/segment.c
matroskaenc: Implement support for ALAC
[ffmpeg] / libavformat / segment.c
1 /*
2  * Generic segmenter
3  * Copyright (c) 2011, Luca Barbato
4  *
5  * This file is part of Libav.
6  *
7  * Libav is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * Libav is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 #include <float.h>
23
24 #include "avformat.h"
25 #include "internal.h"
26
27 #include "libavutil/avassert.h"
28 #include "libavutil/log.h"
29 #include "libavutil/opt.h"
30 #include "libavutil/avstring.h"
31 #include "libavutil/parseutils.h"
32 #include "libavutil/mathematics.h"
33
34 typedef enum {
35     LIST_TYPE_FLAT = 0,
36     LIST_TYPE_EXT,
37     LIST_TYPE_NB,
38 } ListType;
39
40 typedef struct {
41     const AVClass *class;  /**< Class for private options. */
42     int number;
43     AVFormatContext *avf;
44     char *format;          ///< format to use for output segment files
45     char *list;            ///< filename for the segment list file
46     int   list_size;       ///< number of entries for the segment list file
47     ListType list_type;    ///< set the list type
48     AVIOContext *list_pb;  ///< list file put-byte context
49     int  wrap;             ///< number after which the index wraps
50     char *time_str;        ///< segment duration specification string
51     int64_t time;          ///< segment duration
52     char *times_str;       ///< segment times specification string
53     int64_t *times;        ///< list of segment interval specification
54     int nb_times;          ///< number of elments in the times array
55     char *time_delta_str;  ///< approximation value duration used for the segment times
56     int64_t time_delta;
57     int has_video;
58     double start_time, end_time;
59 } SegmentContext;
60
61 static int segment_start(AVFormatContext *s)
62 {
63     SegmentContext *seg = s->priv_data;
64     AVFormatContext *oc = seg->avf;
65     int err = 0;
66
67     if (seg->wrap)
68         seg->number %= seg->wrap;
69
70     if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
71                               s->filename, seg->number++) < 0) {
72         av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", s->filename);
73         return AVERROR(EINVAL);
74     }
75
76     if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
77                           &s->interrupt_callback, NULL)) < 0)
78         return err;
79
80     if (!oc->priv_data && oc->oformat->priv_data_size > 0) {
81         oc->priv_data = av_mallocz(oc->oformat->priv_data_size);
82         if (!oc->priv_data) {
83             avio_close(oc->pb);
84             return AVERROR(ENOMEM);
85         }
86         if (oc->oformat->priv_class) {
87             *(const AVClass**)oc->priv_data = oc->oformat->priv_class;
88             av_opt_set_defaults(oc->priv_data);
89         }
90     }
91
92     if ((err = oc->oformat->write_header(oc)) < 0) {
93         goto fail;
94     }
95
96     return 0;
97
98 fail:
99     av_log(oc, AV_LOG_ERROR, "Failure occurred when starting segment '%s'\n",
100            oc->filename);
101     avio_close(oc->pb);
102     av_freep(&oc->priv_data);
103
104     return err;
105 }
106
107 static int segment_end(AVFormatContext *s)
108 {
109     SegmentContext *seg = s->priv_data;
110     AVFormatContext *oc = seg->avf;
111     int ret = 0;
112
113     if (oc->oformat->write_trailer)
114         ret = oc->oformat->write_trailer(oc);
115
116     if (ret < 0)
117         av_log(s, AV_LOG_ERROR, "Failure occurred when ending segment '%s'\n",
118                oc->filename);
119
120     if (seg->list) {
121         if (seg->list_size && !(seg->number % seg->list_size)) {
122             avio_close(seg->list_pb);
123             if ((ret = avio_open2(&seg->list_pb, seg->list, AVIO_FLAG_WRITE,
124                                   &s->interrupt_callback, NULL)) < 0)
125                 goto end;
126         }
127
128         if (seg->list_type == LIST_TYPE_FLAT) {
129             avio_printf(seg->list_pb, "%s\n", oc->filename);
130         } else if (seg->list_type == LIST_TYPE_EXT) {
131             avio_printf(seg->list_pb, "%s,%f,%f\n", oc->filename, seg->start_time, seg->end_time);
132         }
133         avio_flush(seg->list_pb);
134     }
135
136 end:
137     avio_close(oc->pb);
138     if (oc->oformat->priv_class)
139         av_opt_free(oc->priv_data);
140     av_freep(&oc->priv_data);
141
142     return ret;
143 }
144
145 static int parse_times(void *log_ctx, int64_t **times, int *nb_times,
146                        const char *times_str)
147 {
148     char *p;
149     int i, ret = 0;
150     char *times_str1 = av_strdup(times_str);
151     char *saveptr = NULL;
152
153     if (!times_str1)
154         return AVERROR(ENOMEM);
155
156 #define FAIL(err) ret = err; goto end
157
158     *nb_times = 1;
159     for (p = times_str1; *p; p++)
160         if (*p == ',')
161             (*nb_times)++;
162
163     *times = av_malloc(sizeof(**times) * *nb_times);
164     if (!*times) {
165         av_log(log_ctx, AV_LOG_ERROR, "Could not allocate forced times array\n");
166         FAIL(AVERROR(ENOMEM));
167     }
168
169     p = times_str1;
170     for (i = 0; i < *nb_times; i++) {
171         int64_t t;
172         char *tstr = av_strtok(p, ",", &saveptr);
173         av_assert0(tstr);
174         p = NULL;
175
176         ret = av_parse_time(&t, tstr, 1);
177         if (ret < 0) {
178             av_log(log_ctx, AV_LOG_ERROR,
179                    "Invalid time duration specification in %s\n", p);
180             FAIL(AVERROR(EINVAL));
181         }
182         (*times)[i] = t;
183
184         /* check on monotonicity */
185         if (i && (*times)[i-1] > (*times)[i]) {
186             av_log(log_ctx, AV_LOG_ERROR,
187                    "Specified time %f is greater than the following time %f\n",
188                    (float)((*times)[i])/1000000, (float)((*times)[i-1])/1000000);
189             FAIL(AVERROR(EINVAL));
190         }
191     }
192
193 end:
194     av_free(times_str1);
195     return ret;
196 }
197
198 static int seg_write_header(AVFormatContext *s)
199 {
200     SegmentContext *seg = s->priv_data;
201     AVFormatContext *oc;
202     int ret, i;
203
204     seg->number = 0;
205
206     if (seg->time_str && seg->times_str) {
207         av_log(s, AV_LOG_ERROR,
208                "segment_time and segment_times options are mutually exclusive, select just one of them\n");
209         return AVERROR(EINVAL);
210     }
211
212     if (seg->times_str) {
213         if ((ret = parse_times(s, &seg->times, &seg->nb_times, seg->times_str)) < 0)
214             return ret;
215     } else {
216         /* set default value if not specified */
217         if (!seg->time_str)
218             seg->time_str = av_strdup("2");
219         if ((ret = av_parse_time(&seg->time, seg->time_str, 1)) < 0) {
220             av_log(s, AV_LOG_ERROR,
221                    "Invalid time duration specification '%s' for segment_time option\n",
222                    seg->time_str);
223             return ret;
224         }
225     }
226
227     if (seg->time_delta_str) {
228         if ((ret = av_parse_time(&seg->time_delta, seg->time_delta_str, 1)) < 0) {
229             av_log(s, AV_LOG_ERROR,
230                    "Invalid time duration specification '%s' for delta option\n",
231                    seg->time_delta_str);
232             return ret;
233         }
234     }
235
236     oc = avformat_alloc_context();
237
238     if (!oc)
239         return AVERROR(ENOMEM);
240
241     if (seg->list)
242         if ((ret = avio_open2(&seg->list_pb, seg->list, AVIO_FLAG_WRITE,
243                               &s->interrupt_callback, NULL)) < 0)
244             goto fail;
245
246     for (i = 0; i< s->nb_streams; i++)
247         seg->has_video +=
248             (s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO);
249
250     if (seg->has_video > 1)
251         av_log(s, AV_LOG_WARNING,
252                "More than a single video stream present, "
253                "expect issues decoding it.\n");
254
255     oc->oformat = av_guess_format(seg->format, s->filename, NULL);
256
257     if (!oc->oformat) {
258         ret = AVERROR_MUXER_NOT_FOUND;
259         goto fail;
260     }
261     if (oc->oformat->flags & AVFMT_NOFILE) {
262         av_log(s, AV_LOG_ERROR, "format %s not supported.\n",
263                oc->oformat->name);
264         ret = AVERROR(EINVAL);
265         goto fail;
266     }
267
268     seg->avf = oc;
269
270     oc->streams = s->streams;
271     oc->nb_streams = s->nb_streams;
272
273     if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
274                               s->filename, seg->number++) < 0) {
275         ret = AVERROR(EINVAL);
276         goto fail;
277     }
278
279     if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
280                           &s->interrupt_callback, NULL)) < 0)
281         goto fail;
282
283     if ((ret = avformat_write_header(oc, NULL)) < 0) {
284         avio_close(oc->pb);
285         goto fail;
286     }
287
288 fail:
289     if (ret) {
290         if (oc) {
291             oc->streams = NULL;
292             oc->nb_streams = 0;
293             avformat_free_context(oc);
294         }
295         if (seg->list)
296             avio_close(seg->list_pb);
297     }
298     return ret;
299 }
300
301 static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
302 {
303     SegmentContext *seg = s->priv_data;
304     AVFormatContext *oc = seg->avf;
305     AVStream *st = oc->streams[pkt->stream_index];
306     int64_t end_pts;
307     int ret;
308
309     if (seg->times) {
310         end_pts = seg->number <= seg->nb_times ? seg->times[seg->number-1] : INT64_MAX;
311     } else {
312         end_pts = seg->time * seg->number;
313     }
314
315     /* if the segment has video, start a new segment *only* with a key video frame */
316     if ((st->codec->codec_type == AVMEDIA_TYPE_VIDEO || !seg->has_video) &&
317         av_compare_ts(pkt->pts, st->time_base,
318                       end_pts-seg->time_delta, AV_TIME_BASE_Q) >= 0 &&
319         pkt->flags & AV_PKT_FLAG_KEY) {
320
321         av_log(s, AV_LOG_DEBUG, "Next segment starts with packet stream:%d pts:%"PRId64" pts_time:%f\n",
322                pkt->stream_index, pkt->pts, pkt->pts * av_q2d(st->time_base));
323
324         if ((ret = segment_end(s)) < 0 || (ret = segment_start(s)) < 0)
325             goto fail;
326         seg->start_time = (double)pkt->pts * av_q2d(st->time_base);
327     } else if (pkt->pts != AV_NOPTS_VALUE) {
328         seg->end_time = FFMAX(seg->end_time,
329                               (double)(pkt->pts + pkt->duration) * av_q2d(st->time_base));
330     }
331
332     ret = oc->oformat->write_packet(oc, pkt);
333
334 fail:
335     if (ret < 0) {
336         oc->streams = NULL;
337         oc->nb_streams = 0;
338         if (seg->list)
339             avio_close(seg->list_pb);
340         avformat_free_context(oc);
341     }
342
343     return ret;
344 }
345
346 static int seg_write_trailer(struct AVFormatContext *s)
347 {
348     SegmentContext *seg = s->priv_data;
349     AVFormatContext *oc = seg->avf;
350     int ret = segment_end(s);
351     if (seg->list)
352         avio_close(seg->list_pb);
353
354     av_opt_free(seg);
355     av_freep(&seg->times);
356
357     oc->streams = NULL;
358     oc->nb_streams = 0;
359     avformat_free_context(oc);
360     return ret;
361 }
362
363 #define OFFSET(x) offsetof(SegmentContext, x)
364 #define E AV_OPT_FLAG_ENCODING_PARAM
365 static const AVOption options[] = {
366     { "segment_format",    "set container format used for the segments", OFFSET(format),  AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
367     { "segment_list",      "set the segment list filename",              OFFSET(list),    AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
368     { "segment_list_size", "set the maximum number of playlist entries", OFFSET(list_size), AV_OPT_TYPE_INT,  {.dbl = 5},     0, INT_MAX, E },
369     { "segment_list_type", "set the segment list type",                  OFFSET(list_type), AV_OPT_TYPE_INT,  {.dbl = LIST_TYPE_FLAT}, 0, LIST_TYPE_NB-1, E, "list_type" },
370     { "flat", "flat format",     0, AV_OPT_TYPE_CONST, {.dbl=LIST_TYPE_FLAT }, INT_MIN, INT_MAX, 0, "list_type" },
371     { "ext",  "extended format", 0, AV_OPT_TYPE_CONST, {.dbl=LIST_TYPE_EXT  }, INT_MIN, INT_MAX, 0, "list_type" },
372     { "segment_time",      "set segment duration",                       OFFSET(time_str),AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
373     { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta_str), AV_OPT_TYPE_STRING, {.str = "0"}, 0, 0, E },
374     { "segment_times",     "set segment split time points",              OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL},  0, 0,       E },
375     { "segment_wrap",      "set number after which the index wraps",     OFFSET(wrap),    AV_OPT_TYPE_INT,    {.dbl = 0},     0, INT_MAX, E },
376     { NULL },
377 };
378
379 static const AVClass seg_class = {
380     .class_name = "segment muxer",
381     .item_name  = av_default_item_name,
382     .option     = options,
383     .version    = LIBAVUTIL_VERSION_INT,
384 };
385
386 AVOutputFormat ff_segment_muxer = {
387     .name           = "segment",
388     .long_name      = NULL_IF_CONFIG_SMALL("segment"),
389     .priv_data_size = sizeof(SegmentContext),
390     .flags          = AVFMT_GLOBALHEADER | AVFMT_NOFILE,
391     .write_header   = seg_write_header,
392     .write_packet   = seg_write_packet,
393     .write_trailer  = seg_write_trailer,
394     .priv_class     = &seg_class,
395 };
396
397 static const AVClass sseg_class = {
398     .class_name = "stream_segment muxer",
399     .item_name  = av_default_item_name,
400     .option     = options,
401     .version    = LIBAVUTIL_VERSION_INT,
402 };
403
404 AVOutputFormat ff_stream_segment_muxer = {
405     .name           = "stream_segment,ssegment",
406     .long_name      = NULL_IF_CONFIG_SMALL("streaming segment muxer"),
407     .priv_data_size = sizeof(SegmentContext),
408     .flags          = AVFMT_NOFILE,
409     .write_header   = seg_write_header,
410     .write_packet   = seg_write_packet,
411     .write_trailer  = seg_write_trailer,
412     .priv_class     = &sseg_class,
413 };