~ubuntu-branches/ubuntu/trusty/libav/trusty-proposed

« back to all changes in this revision

Viewing changes to libavformat/segment.c

  • Committer: Package Import Robot
  • Author(s): Reinhard Tartler
  • Date: 2013-10-22 23:24:08 UTC
  • mfrom: (1.3.36 sid)
  • Revision ID: package-import@ubuntu.com-20131022232408-b8tvvn4pyzri9mi3
Tags: 6:9.10-1ubuntu1
* Build all -extra flavors from this source package, as libav got demoted
  from main to universe, cf LP: #1243235
* Simplify debian/rules to follow exactly the code that debian executes
* New upstream (LP: #1180288) fixes lots of security issues (LP: #1242802)
* Merge from unstable, remaining changes:
  - build-depend on libtiff5-dev rather than libtiff4-dev,
    avoids FTBFS caused by imlib
  - follow the regular debian codepaths

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
20
 */
21
21
 
22
 
#include <strings.h>
23
22
#include <float.h>
24
23
 
25
24
#include "avformat.h"
34
33
typedef struct {
35
34
    const AVClass *class;  /**< Class for private options. */
36
35
    int number;
 
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;
44
48
    int has_video;
45
49
    AVIOContext *pb;
46
50
} SegmentContext;
47
51
 
48
 
static int segment_start(AVFormatContext *s)
 
52
enum {
 
53
    LIST_FLAT,
 
54
    LIST_HLS
 
55
};
 
56
 
 
57
static int segment_mux_init(AVFormatContext *s)
 
58
{
 
59
    SegmentContext *seg = s->priv_data;
 
60
    AVFormatContext *oc;
 
61
    int i;
 
62
 
 
63
    seg->avf = oc = avformat_alloc_context();
 
64
    if (!oc)
 
65
        return AVERROR(ENOMEM);
 
66
 
 
67
    oc->oformat            = seg->oformat;
 
68
    oc->interrupt_callback = s->interrupt_callback;
 
69
 
 
70
    for (i = 0; i < s->nb_streams; i++) {
 
71
        AVStream *st;
 
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;
 
76
    }
 
77
 
 
78
    return 0;
 
79
}
 
80
 
 
81
static int segment_hls_window(AVFormatContext *s, int last)
 
82
{
 
83
    SegmentContext *seg = s->priv_data;
 
84
    int i, ret = 0;
 
85
    char buf[1024];
 
86
 
 
87
    if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE,
 
88
                              &s->interrupt_callback, NULL)) < 0)
 
89
        goto fail;
 
90
 
 
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));
 
96
 
 
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);
 
102
    }
 
103
 
 
104
    if (last)
 
105
        avio_printf(seg->pb, "#EXT-X-ENDLIST\n");
 
106
fail:
 
107
    avio_closep(&seg->pb);
 
108
    return ret;
 
109
}
 
110
 
 
111
static int segment_start(AVFormatContext *s, int write_header)
49
112
{
50
113
    SegmentContext *c = s->priv_data;
51
114
    AVFormatContext *oc = c->avf;
52
115
    int err = 0;
53
116
 
 
117
    if (write_header) {
 
118
        avformat_free_context(oc);
 
119
        c->avf = NULL;
 
120
        if ((err = segment_mux_init(s)) < 0)
 
121
            return err;
 
122
        oc = c->avf;
 
123
    }
 
124
 
 
125
    if (c->wrap)
 
126
        c->number %= c->wrap;
 
127
 
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)
60
134
        return err;
61
135
 
62
 
    if (!oc->priv_data && oc->oformat->priv_data_size > 0) {
63
 
        oc->priv_data = av_mallocz(oc->oformat->priv_data_size);
64
 
        if (!oc->priv_data) {
65
 
            avio_close(oc->pb);
66
 
            return AVERROR(ENOMEM);
67
 
        }
68
 
        if (oc->oformat->priv_class) {
69
 
            *(const AVClass**)oc->priv_data = oc->oformat->priv_class;
70
 
            av_opt_set_defaults(oc->priv_data);
71
 
        }
72
 
    }
 
136
    if (oc->oformat->priv_class && oc->priv_data)
 
137
        av_opt_set(oc->priv_data, "resend_headers", "1", 0); /* mpegts specific */
73
138
 
74
 
    if ((err = oc->oformat->write_header(oc)) < 0) {
75
 
        goto fail;
 
139
    if (write_header) {
 
140
        if ((err = avformat_write_header(oc, NULL)) < 0)
 
141
            return err;
76
142
    }
77
143
 
78
144
    return 0;
79
 
 
80
 
fail:
81
 
    avio_close(oc->pb);
82
 
    av_freep(&oc->priv_data);
83
 
 
84
 
    return err;
85
145
}
86
146
 
87
 
static int segment_end(AVFormatContext *oc)
 
147
static int segment_end(AVFormatContext *oc, int write_trailer)
88
148
{
89
149
    int ret = 0;
90
150
 
91
 
    if (oc->oformat->write_trailer)
92
 
        ret = oc->oformat->write_trailer(oc);
93
 
 
 
151
    av_write_frame(oc, NULL); /* Flush any buffered data (fragmented mp4) */
 
152
    if (write_trailer)
 
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);
98
155
 
99
156
    return ret;
100
157
}
101
158
 
 
159
static int open_null_ctx(AVIOContext **ctx)
 
160
{
 
161
    int buf_size = 32768;
 
162
    uint8_t *buf = av_malloc(buf_size);
 
163
    if (!buf)
 
164
        return AVERROR(ENOMEM);
 
165
    *ctx = avio_alloc_context(buf, buf_size, AVIO_FLAG_WRITE, NULL, NULL, NULL, NULL);
 
166
    if (!*ctx) {
 
167
        av_free(buf);
 
168
        return AVERROR(ENOMEM);
 
169
    }
 
170
    return 0;
 
171
}
 
172
 
 
173
static void close_null_ctx(AVIOContext *pb)
 
174
{
 
175
    av_free(pb->buffer);
 
176
    av_free(pb);
 
177
}
 
178
 
102
179
static int seg_write_header(AVFormatContext *s)
103
180
{
104
181
    SegmentContext *seg = s->priv_data;
105
 
    AVFormatContext *oc;
 
182
    AVFormatContext *oc = NULL;
106
183
    int ret, i;
107
184
 
108
185
    seg->number = 0;
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;
111
190
 
112
 
    if (seg->list)
 
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)
115
 
            return ret;
 
194
            goto fail;
116
195
 
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);
120
199
 
123
202
               "More than a single video stream present, "
124
203
               "expect issues decoding it.\n");
125
204
 
126
 
    oc = avformat_alloc_context();
127
 
 
128
 
    if (!oc) {
129
 
        ret = AVERROR(ENOMEM);
130
 
        goto fail;
131
 
    }
132
 
 
133
 
    oc->oformat = av_guess_format(seg->format, s->filename, NULL);
134
 
 
135
 
    if (!oc->oformat) {
 
205
    seg->oformat = av_guess_format(seg->format, s->filename, NULL);
 
206
 
 
207
    if (!seg->oformat) {
136
208
        ret = AVERROR_MUXER_NOT_FOUND;
137
209
        goto fail;
138
210
    }
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",
141
 
               oc->oformat->name);
 
213
               seg->oformat->name);
142
214
        ret = AVERROR(EINVAL);
143
215
        goto fail;
144
216
    }
145
217
 
146
 
    seg->avf = oc;
147
 
 
148
 
    oc->streams = s->streams;
149
 
    oc->nb_streams = s->nb_streams;
 
218
    if ((ret = segment_mux_init(s)) < 0)
 
219
        goto fail;
 
220
    oc = seg->avf;
150
221
 
151
222
    if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
152
223
                              s->filename, seg->number++) < 0) {
154
225
        goto fail;
155
226
    }
156
227
 
157
 
    if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
158
 
                          &s->interrupt_callback, NULL)) < 0)
159
 
        goto fail;
 
228
    if (seg->write_header_trailer) {
 
229
        if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
 
230
                              &s->interrupt_callback, NULL)) < 0)
 
231
            goto fail;
 
232
    } else {
 
233
        if ((ret = open_null_ctx(&oc->pb)) < 0)
 
234
            goto fail;
 
235
    }
160
236
 
161
237
    if ((ret = avformat_write_header(oc, NULL)) < 0) {
162
238
        avio_close(oc->pb);
163
239
        goto fail;
164
240
    }
165
241
 
 
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)
 
246
            goto fail;
 
247
    }
 
248
 
166
249
    if (seg->list) {
167
 
        avio_printf(seg->pb, "%s\n", oc->filename);
168
 
        avio_flush(seg->pb);
 
250
        if (seg->list_type == LIST_HLS) {
 
251
            if ((ret = segment_hls_window(s, 0)) < 0)
 
252
                goto fail;
 
253
        } else {
 
254
            avio_printf(seg->pb, "%s\n", oc->filename);
 
255
            avio_flush(seg->pb);
 
256
        }
169
257
    }
170
258
 
171
259
fail:
172
260
    if (ret) {
173
 
        oc->streams = NULL;
174
 
        oc->nb_streams = 0;
175
261
        if (seg->list)
176
262
            avio_close(seg->pb);
177
 
        avformat_free_context(oc);
 
263
        if (seg->avf)
 
264
            avformat_free_context(seg->avf);
178
265
    }
179
266
    return ret;
180
267
}
183
270
{
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;
188
 
    int ret;
189
 
 
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) {
194
 
 
 
275
    int ret, can_split = 1;
 
276
 
 
277
    if (seg->has_video) {
 
278
        can_split = st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
 
279
                    pkt->flags & AV_PKT_FLAG_KEY;
 
280
    }
 
281
 
 
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);
197
286
 
198
 
        ret = segment_end(oc);
 
287
        ret = segment_end(oc, seg->individual_header_trailer);
199
288
 
200
289
        if (!ret)
201
 
            ret = segment_start(s);
 
290
            ret = segment_start(s, seg->individual_header_trailer);
202
291
 
203
292
        if (ret)
204
293
            goto fail;
205
294
 
 
295
        oc = seg->avf;
 
296
 
206
297
        if (seg->list) {
207
 
            avio_printf(seg->pb, "%s\n", oc->filename);
208
 
            avio_flush(seg->pb);
209
 
            if (!(seg->number % seg->size)) {
210
 
                avio_close(seg->pb);
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)
213
300
                    goto fail;
214
 
 
 
301
            } else {
 
302
                avio_printf(seg->pb, "%s\n", oc->filename);
 
303
                avio_flush(seg->pb);
 
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)
 
308
                        goto fail;
 
309
                }
215
310
            }
216
311
        }
217
312
    }
218
313
 
219
 
    ret = oc->oformat->write_packet(oc, pkt);
 
314
    ret = ff_write_chained(oc, pkt->stream_index, pkt, s);
220
315
 
221
316
fail:
222
317
    if (ret < 0) {
223
 
        oc->streams = NULL;
224
 
        oc->nb_streams = 0;
225
318
        if (seg->list)
226
319
            avio_close(seg->pb);
227
320
        avformat_free_context(oc);
234
327
{
235
328
    SegmentContext *seg = s->priv_data;
236
329
    AVFormatContext *oc = seg->avf;
237
 
    int ret = segment_end(oc);
238
 
    if (seg->list)
239
 
        avio_close(seg->pb);
240
 
    oc->streams = NULL;
241
 
    oc->nb_streams = 0;
 
330
    int ret;
 
331
    if (!seg->write_header_trailer) {
 
332
        if ((ret = segment_end(oc, 0)) < 0)
 
333
            goto fail;
 
334
        open_null_ctx(&oc->pb);
 
335
        ret = av_write_trailer(oc);
 
336
        close_null_ctx(oc->pb);
 
337
    } else {
 
338
        ret = segment_end(oc, 1);
 
339
    }
 
340
 
 
341
    if (ret < 0)
 
342
        goto fail;
 
343
 
 
344
    if (seg->list && seg->list_type == LIST_HLS) {
 
345
        if ((ret = segment_hls_window(s, 1) < 0))
 
346
            goto fail;
 
347
    }
 
348
 
 
349
fail:
 
350
    avio_close(seg->pb);
242
351
    avformat_free_context(oc);
243
352
    return ret;
244
353
}
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 },
253
368
    { NULL },
254
369
};
255
370
 
263
378
 
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,