Main Page
Related Pages
Modules
Data Structures
Files
Examples
File List
Globals
libavformat
segment.c
Go to the documentation of this file.
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 <strings.h>
23
#include <float.h>
24
25
#include "
avformat.h
"
26
#include "
internal.h
"
27
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
struct
{
35
const
AVClass
*
class
;
36
int
number
;
37
AVFormatContext
*
avf
;
38
char
*
format
;
39
char
*
list
;
40
float
time
;
41
int
size
;
42
int64_t
offset_time
;
43
int64_t
recording_time
;
44
int
has_video
;
45
AVIOContext
*
pb
;
46
}
SegmentContext
;
47
48
static
int
segment_start
(
AVFormatContext
*s)
49
{
50
SegmentContext
*c = s->
priv_data
;
51
AVFormatContext
*oc = c->
avf
;
52
int
err = 0;
53
54
if
(
av_get_frame_filename
(oc->
filename
,
sizeof
(oc->
filename
),
55
s->
filename
, c->
number
++) < 0)
56
return
AVERROR
(EINVAL);
57
58
if
((err =
avio_open2
(&oc->
pb
, oc->
filename
,
AVIO_FLAG_WRITE
,
59
&s->
interrupt_callback
,
NULL
)) < 0)
60
return
err;
61
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
}
73
74
if
((err = oc->
oformat
->
write_header
(oc)) < 0) {
75
goto
fail;
76
}
77
78
return
0;
79
80
fail:
81
avio_close
(oc->
pb
);
82
av_freep
(&oc->
priv_data
);
83
84
return
err;
85
}
86
87
static
int
segment_end
(
AVFormatContext
*oc)
88
{
89
int
ret = 0;
90
91
if
(oc->
oformat
->
write_trailer
)
92
ret = oc->
oformat
->
write_trailer
(oc);
93
94
avio_close
(oc->
pb
);
95
if
(oc->
oformat
->
priv_class
)
96
av_opt_free
(oc->
priv_data
);
97
av_freep
(&oc->
priv_data
);
98
99
return
ret;
100
}
101
102
static
int
seg_write_header
(
AVFormatContext
*s)
103
{
104
SegmentContext
*seg = s->
priv_data
;
105
AVFormatContext
*oc;
106
int
ret, i;
107
108
seg->
number
= 0;
109
seg->
offset_time
= 0;
110
seg->
recording_time
= seg->
time
* 1000000;
111
112
if
(seg->
list
)
113
if
((ret =
avio_open2
(&seg->
pb
, seg->
list
,
AVIO_FLAG_WRITE
,
114
&s->
interrupt_callback
,
NULL
)) < 0)
115
return
ret;
116
117
for
(i = 0; i< s->
nb_streams
; i++)
118
seg->
has_video
+=
119
(s->
streams
[i]->
codec
->
codec_type
==
AVMEDIA_TYPE_VIDEO
);
120
121
if
(seg->
has_video
> 1)
122
av_log
(s,
AV_LOG_WARNING
,
123
"More than a single video stream present, "
124
"expect issues decoding it.\n"
);
125
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
) {
136
ret =
AVERROR_MUXER_NOT_FOUND
;
137
goto
fail;
138
}
139
if
(oc->
oformat
->
flags
&
AVFMT_NOFILE
) {
140
av_log
(s,
AV_LOG_ERROR
,
"format %s not supported.\n"
,
141
oc->
oformat
->
name
);
142
ret =
AVERROR
(EINVAL);
143
goto
fail;
144
}
145
146
seg->
avf
= oc;
147
148
oc->
streams
= s->
streams
;
149
oc->
nb_streams
= s->
nb_streams
;
150
151
if
(
av_get_frame_filename
(oc->
filename
,
sizeof
(oc->
filename
),
152
s->
filename
, seg->
number
++) < 0) {
153
ret =
AVERROR
(EINVAL);
154
goto
fail;
155
}
156
157
if
((ret =
avio_open2
(&oc->
pb
, oc->
filename
,
AVIO_FLAG_WRITE
,
158
&s->
interrupt_callback
,
NULL
)) < 0)
159
goto
fail;
160
161
if
((ret =
avformat_write_header
(oc,
NULL
)) < 0) {
162
avio_close
(oc->
pb
);
163
goto
fail;
164
}
165
166
if
(seg->
list
) {
167
avio_printf
(seg->
pb
,
"%s\n"
, oc->
filename
);
168
avio_flush
(seg->
pb
);
169
}
170
171
fail:
172
if
(ret) {
173
oc->
streams
=
NULL
;
174
oc->
nb_streams
= 0;
175
if
(seg->
list
)
176
avio_close
(seg->
pb
);
177
avformat_free_context
(oc);
178
}
179
return
ret;
180
}
181
182
static
int
seg_write_packet
(
AVFormatContext
*s,
AVPacket
*pkt)
183
{
184
SegmentContext
*seg = s->
priv_data
;
185
AVFormatContext
*oc = seg->
avf
;
186
AVStream
*st = oc->
streams
[pkt->
stream_index
];
187
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
195
av_log
(s,
AV_LOG_DEBUG
,
"Next segment starts at %d %"
PRId64
"\n"
,
196
pkt->
stream_index
, pkt->
pts
);
197
198
ret =
segment_end
(oc);
199
200
if
(!ret)
201
ret =
segment_start
(s);
202
203
if
(ret)
204
goto
fail;
205
206
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)
213
goto
fail;
214
215
}
216
}
217
}
218
219
ret = oc->
oformat
->
write_packet
(oc, pkt);
220
221
fail:
222
if
(ret < 0) {
223
oc->
streams
=
NULL
;
224
oc->
nb_streams
= 0;
225
if
(seg->
list
)
226
avio_close
(seg->
pb
);
227
avformat_free_context
(oc);
228
}
229
230
return
ret;
231
}
232
233
static
int
seg_write_trailer
(
struct
AVFormatContext
*s)
234
{
235
SegmentContext
*seg = s->
priv_data
;
236
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;
242
avformat_free_context
(oc);
243
return
ret;
244
}
245
246
#define OFFSET(x) offsetof(SegmentContext, x)
247
#define E AV_OPT_FLAG_ENCODING_PARAM
248
static
const
AVOption
options
[] = {
249
{
"segment_format"
,
"container format used for the segments"
,
OFFSET
(format),
AV_OPT_TYPE_STRING
, {.str =
NULL
}, 0, 0,
E
},
250
{
"segment_time"
,
"segment length in seconds"
,
OFFSET
(
time
),
AV_OPT_TYPE_FLOAT
, {.dbl = 2}, 0, FLT_MAX,
E
},
251
{
"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
},
253
{
NULL
},
254
};
255
256
static
const
AVClass
seg_class
= {
257
.
class_name
=
"segment muxer"
,
258
.item_name =
av_default_item_name
,
259
.option =
options
,
260
.version =
LIBAVUTIL_VERSION_INT
,
261
};
262
263
264
AVOutputFormat
ff_segment_muxer
= {
265
.
name
=
"segment"
,
266
.long_name =
NULL_IF_CONFIG_SMALL
(
"segment muxer"
),
267
.priv_data_size =
sizeof
(
SegmentContext
),
268
.
flags
=
AVFMT_GLOBALHEADER
|
AVFMT_NOFILE
,
269
.
write_header
=
seg_write_header
,
270
.
write_packet
=
seg_write_packet
,
271
.
write_trailer
=
seg_write_trailer
,
272
.priv_class = &seg_class,
273
};