]> git.sesse.net Git - ffmpeg/blob - libavformat/segment.c
Merge remote-tracking branch 'qatar/master'
[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 "libavutil/avstring.h"
23 #include "libavutil/log.h"
24 #include "libavutil/opt.h"
25 #include "libavutil/mathematics.h"
26 #include "libavutil/parseutils.h"
27 #include "avformat.h"
28 #include "internal.h"
29 #include <strings.h>
30 #include <float.h>
31
32 typedef struct {
33     const AVClass *class;  /**< Class for private options. */
34     int number;
35     AVFormatContext *avf;
36     char *format;          /**< Set by a private option. */
37     char *pattern;         /**< Set by a private option. */
38     char *path;            /**< Set by a private option. */
39     float time;            /**< Set by a private option. */
40     int64_t offset_time;
41     int64_t recording_time;
42 } SegmentContext;
43
44 #if CONFIG_SEGMENT_MUXER
45
46 static int segment_header(SegmentContext *s)
47 {
48     AVFormatContext *oc = s->avf;
49     int err = 0;
50
51     av_strlcpy(oc->filename, s->path, sizeof(oc->filename));
52
53     av_strlcatf(oc->filename, sizeof(oc->filename),
54                 s->pattern, s->number++);
55
56     if ((err = avio_open(&oc->pb, oc->filename, AVIO_FLAG_WRITE)) < 0) {
57         return err;
58     }
59
60     if (!oc->priv_data && oc->oformat->priv_data_size > 0) {
61         oc->priv_data = av_mallocz(oc->oformat->priv_data_size);
62         if (!oc->priv_data) {
63             avio_close(oc->pb);
64             return AVERROR(ENOMEM);
65         }
66     }
67
68     if ((err = oc->oformat->write_header(oc)) < 0) {
69         avio_close(oc->pb);
70         av_freep(&oc->priv_data);
71     }
72
73     return err;
74 }
75
76 static int segment_trailer(AVFormatContext *oc)
77 {
78     int ret = 0;
79
80     if(oc->oformat->write_trailer)
81         ret = oc->oformat->write_trailer(oc);
82
83     avio_close(oc->pb);
84     av_freep(&oc->priv_data);
85
86     return ret;
87 }
88
89 static int seg_write_header(AVFormatContext *s)
90 {
91     SegmentContext *seg = s->priv_data;
92     AVFormatContext *oc;
93     int ret;
94
95     seg->number = 0;
96     seg->recording_time = seg->time*1000000;
97     seg->offset_time = 0;
98
99     if (!seg->path) {
100         char *t;
101         seg->path = av_strdup(s->filename);
102         t = strrchr(seg->path, '.');
103         if (t) *t = '\0';
104     }
105
106     oc = avformat_alloc_context();
107
108     if (!oc) {
109         return AVERROR(ENOMEM);
110     }
111
112     oc->oformat = av_guess_format(seg->format, NULL, NULL);
113
114     if (!oc->oformat) {
115         avformat_free_context(oc);
116         return AVERROR_MUXER_NOT_FOUND;
117     }
118
119     seg->avf = oc;
120
121     oc->streams = s->streams;
122     oc->nb_streams = s->nb_streams;
123
124     av_strlcpy(oc->filename, seg->path, sizeof(oc->filename));
125
126     av_strlcatf(oc->filename, sizeof(oc->filename),
127                 seg->pattern, seg->number++);
128
129     if ((ret = avio_open(&oc->pb, oc->filename, AVIO_FLAG_WRITE)) < 0) {
130         avformat_free_context(oc);
131         return ret;
132     }
133
134     if ((ret = avformat_write_header(oc, NULL)) < 0) {
135         avio_close(oc->pb);
136     }
137
138     if (ret)
139         avformat_free_context(oc);
140
141     avio_printf(s->pb, "%s\n", oc->filename);
142     avio_flush(s->pb);
143
144     return ret;
145 }
146
147 static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
148 {
149     SegmentContext *seg = s->priv_data;
150     AVFormatContext *oc = seg->avf;
151     AVStream *st = oc->streams[pkt->stream_index];
152     int ret;
153
154     if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
155         av_compare_ts(pkt->pts, st->time_base,
156                   seg->recording_time*seg->number,
157                               (AVRational){1, 1000000}) >= 0 &&
158         pkt->flags & AV_PKT_FLAG_KEY) {
159         av_log(s, AV_LOG_INFO, "I'd reset at %d %"PRId64"\n",
160                pkt->stream_index, pkt->pts);
161
162         ret = segment_trailer(oc);
163         if (!ret)
164             ret = segment_header(seg);
165
166         if (ret) {
167             avformat_free_context(oc);
168             return ret;
169         }
170         avio_printf(s->pb, "%s\n", oc->filename);
171         avio_flush(s->pb);
172     }
173
174     ret = oc->oformat->write_packet(oc, pkt);
175
176     return ret;
177 }
178
179 static int seg_write_trailer(struct AVFormatContext *s)
180 {
181     SegmentContext *seg = s->priv_data;
182     AVFormatContext *oc = seg->avf;
183
184     return segment_trailer(oc);
185 }
186
187 #endif /* CONFIG_SEGMENT_MUXER */
188
189 #define OFFSET(x) offsetof(SegmentContext, x)
190 #define E AV_OPT_FLAG_ENCODING_PARAM
191 static const AVOption options[] = {
192     { "container_format", "container format used for the segments", OFFSET(format), AV_OPT_TYPE_STRING, {.str = "nut"},  0, 0, E },
193     { "segment_time",     "segment lenght in seconds",              OFFSET(time),   AV_OPT_TYPE_FLOAT,  {.dbl = 2},      0, FLT_MAX, E },
194     { "segment_pattern",  "pattern to use in segment files",        OFFSET(pattern),AV_OPT_TYPE_STRING, {.str = "%03d"}, 0, 0, E },
195     { "segment_basename", "basename to use in segment files",       OFFSET(path   ),AV_OPT_TYPE_STRING, {.str = NULL},   0, 0, E },
196     { NULL },
197 };
198
199 static const AVClass seg_class = {
200     .class_name = "segment muxer",
201     .item_name  = av_default_item_name,
202     .option     = options,
203     .version    = LIBAVUTIL_VERSION_INT,
204 };
205
206 /* input
207 #if CONFIG_IMAGE2_DEMUXER
208 AVInputFormat ff_image2_demuxer = {
209     .name           = "image2",
210     .long_name      = NULL_IF_CONFIG_SMALL("image2 sequence"),
211     .priv_data_size = sizeof(VideoData),
212     .read_probe     = read_probe,
213     .read_header    = read_header,
214     .read_packet    = read_packet,
215     .flags          = AVFMT_NOFILE,
216     .priv_class     = &img2_class,
217 };
218 #endif
219 */
220
221 /* output */
222 #if CONFIG_SEGMENT_MUXER
223 AVOutputFormat ff_segment_muxer = {
224     .name           = "segment",
225     .long_name      = NULL_IF_CONFIG_SMALL("segment muxer"),
226     .extensions     = "m3u8",
227     .priv_data_size = sizeof(SegmentContext),
228     .flags          = AVFMT_GLOBALHEADER,
229     .write_header   = seg_write_header,
230     .write_packet   = seg_write_packet,
231     .write_trailer  = seg_write_trailer,
232     .priv_class     = &seg_class,
233 };
234 #endif