2 * Copyright (c) 2012 Nicolas George
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "libavutil/avassert.h"
22 #include "libavutil/avstring.h"
23 #include "libavutil/intreadwrite.h"
24 #include "libavutil/opt.h"
25 #include "libavutil/parseutils.h"
30 typedef enum ConcatMatchMode
{
35 typedef struct ConcatStream
{
36 AVBitStreamFilterContext
*bsf
;
44 ConcatStream
*streams
;
56 ConcatMatchMode stream_match_mode
;
57 unsigned auto_convert
;
60 static int concat_probe(AVProbeData
*probe
)
62 return memcmp(probe
->buf
, "ffconcat version 1.0", 20) ?
63 0 : AVPROBE_SCORE_MAX
;
66 static char *get_keyword(uint8_t **cursor
)
68 char *ret
= *cursor
+= strspn(*cursor
, SPACE_CHARS
);
69 *cursor
+= strcspn(*cursor
, SPACE_CHARS
);
72 *cursor
+= strspn(*cursor
, SPACE_CHARS
);
77 static int safe_filename(const char *f
)
79 const char *start
= f
;
83 if (!((unsigned)((*f
| 32) - 'a') < 26 ||
84 (unsigned)(*f
- '0') < 10 || *f
== '_' || *f
== '-')) {
96 #define FAIL(retcode) do { ret = (retcode); goto fail; } while(0)
98 static int add_file(AVFormatContext
*avf
, char *filename
, ConcatFile
**rfile
,
99 unsigned *nb_files_alloc
)
101 ConcatContext
*cat
= avf
->priv_data
;
105 size_t url_len
, proto_len
;
108 if (cat
->safe
> 0 && !safe_filename(filename
)) {
109 av_log(avf
, AV_LOG_ERROR
, "Unsafe file name '%s'\n", filename
);
110 FAIL(AVERROR(EPERM
));
113 proto
= avio_find_protocol_name(filename
);
114 proto_len
= proto
? strlen(proto
) : 0;
115 if (!memcmp(filename
, proto
, proto_len
) &&
116 (filename
[proto_len
] == ':' || filename
[proto_len
] == ',')) {
120 url_len
= strlen(avf
->filename
) + strlen(filename
) + 16;
121 if (!(url
= av_malloc(url_len
)))
122 FAIL(AVERROR(ENOMEM
));
123 ff_make_absolute_url(url
, url_len
, avf
->filename
, filename
);
127 if (cat
->nb_files
>= *nb_files_alloc
) {
128 size_t n
= FFMAX(*nb_files_alloc
* 2, 16);
129 ConcatFile
*new_files
;
130 if (n
<= cat
->nb_files
|| n
> SIZE_MAX
/ sizeof(*cat
->files
) ||
131 !(new_files
= av_realloc(cat
->files
, n
* sizeof(*cat
->files
))))
132 FAIL(AVERROR(ENOMEM
));
133 cat
->files
= new_files
;
137 file
= &cat
->files
[cat
->nb_files
++];
138 memset(file
, 0, sizeof(*file
));
142 file
->start_time
= AV_NOPTS_VALUE
;
143 file
->duration
= AV_NOPTS_VALUE
;
153 static int copy_stream_props(AVStream
*st
, AVStream
*source_st
)
157 if (st
->codec
->codec_id
|| !source_st
->codec
->codec_id
) {
158 if (st
->codec
->extradata_size
< source_st
->codec
->extradata_size
) {
159 ret
= ff_alloc_extradata(st
->codec
,
160 source_st
->codec
->extradata_size
);
164 memcpy(st
->codec
->extradata
, source_st
->codec
->extradata
,
165 source_st
->codec
->extradata_size
);
168 if ((ret
= avcodec_copy_context(st
->codec
, source_st
->codec
)) < 0)
170 st
->r_frame_rate
= source_st
->r_frame_rate
;
171 st
->avg_frame_rate
= source_st
->avg_frame_rate
;
172 st
->time_base
= source_st
->time_base
;
173 st
->sample_aspect_ratio
= source_st
->sample_aspect_ratio
;
177 static int detect_stream_specific(AVFormatContext
*avf
, int idx
)
179 ConcatContext
*cat
= avf
->priv_data
;
180 AVStream
*st
= cat
->avf
->streams
[idx
];
181 ConcatStream
*cs
= &cat
->cur_file
->streams
[idx
];
182 AVBitStreamFilterContext
*bsf
;
184 if (cat
->auto_convert
&& st
->codec
->codec_id
== AV_CODEC_ID_H264
&&
185 (st
->codec
->extradata_size
< 4 || AV_RB32(st
->codec
->extradata
) != 1)) {
186 av_log(cat
->avf
, AV_LOG_INFO
,
187 "Auto-inserting h264_mp4toannexb bitstream filter\n");
188 if (!(bsf
= av_bitstream_filter_init("h264_mp4toannexb"))) {
189 av_log(avf
, AV_LOG_ERROR
, "h264_mp4toannexb bitstream filter "
190 "required for H.264 streams\n");
191 return AVERROR_BSF_NOT_FOUND
;
198 static int match_streams_one_to_one(AVFormatContext
*avf
)
200 ConcatContext
*cat
= avf
->priv_data
;
204 for (i
= cat
->cur_file
->nb_streams
; i
< cat
->avf
->nb_streams
; i
++) {
205 if (i
< avf
->nb_streams
) {
206 st
= avf
->streams
[i
];
208 if (!(st
= avformat_new_stream(avf
, NULL
)))
209 return AVERROR(ENOMEM
);
211 if ((ret
= copy_stream_props(st
, cat
->avf
->streams
[i
])) < 0)
213 cat
->cur_file
->streams
[i
].out_stream_index
= i
;
218 static int match_streams_exact_id(AVFormatContext
*avf
)
220 ConcatContext
*cat
= avf
->priv_data
;
224 for (i
= cat
->cur_file
->nb_streams
; i
< cat
->avf
->nb_streams
; i
++) {
225 st
= cat
->avf
->streams
[i
];
226 for (j
= 0; j
< avf
->nb_streams
; j
++) {
227 if (avf
->streams
[j
]->id
== st
->id
) {
228 av_log(avf
, AV_LOG_VERBOSE
,
229 "Match slave stream #%d with stream #%d id 0x%x\n",
231 if ((ret
= copy_stream_props(avf
->streams
[j
], st
)) < 0)
233 cat
->cur_file
->streams
[i
].out_stream_index
= j
;
240 static int match_streams(AVFormatContext
*avf
)
242 ConcatContext
*cat
= avf
->priv_data
;
246 if (cat
->cur_file
->nb_streams
>= cat
->avf
->nb_streams
)
248 map
= av_realloc(cat
->cur_file
->streams
,
249 cat
->avf
->nb_streams
* sizeof(*map
));
251 return AVERROR(ENOMEM
);
252 cat
->cur_file
->streams
= map
;
253 memset(map
+ cat
->cur_file
->nb_streams
, 0,
254 (cat
->avf
->nb_streams
- cat
->cur_file
->nb_streams
) * sizeof(*map
));
256 for (i
= cat
->cur_file
->nb_streams
; i
< cat
->avf
->nb_streams
; i
++)
257 map
[i
].out_stream_index
= -1;
258 switch (cat
->stream_match_mode
) {
259 case MATCH_ONE_TO_ONE
:
260 ret
= match_streams_one_to_one(avf
);
263 ret
= match_streams_exact_id(avf
);
270 for (i
= cat
->cur_file
->nb_streams
; i
< cat
->avf
->nb_streams
; i
++)
271 if ((ret
= detect_stream_specific(avf
, i
)) < 0)
273 cat
->cur_file
->nb_streams
= cat
->avf
->nb_streams
;
277 static int open_file(AVFormatContext
*avf
, unsigned fileno
)
279 ConcatContext
*cat
= avf
->priv_data
;
280 ConcatFile
*file
= &cat
->files
[fileno
];
284 avformat_close_input(&cat
->avf
);
286 cat
->avf
= avformat_alloc_context();
288 return AVERROR(ENOMEM
);
290 cat
->avf
->interrupt_callback
= avf
->interrupt_callback
;
291 if ((ret
= avformat_open_input(&cat
->avf
, file
->url
, NULL
, NULL
)) < 0 ||
292 (ret
= avformat_find_stream_info(cat
->avf
, NULL
)) < 0) {
293 av_log(avf
, AV_LOG_ERROR
, "Impossible to open '%s'\n", file
->url
);
294 avformat_close_input(&cat
->avf
);
297 cat
->cur_file
= file
;
298 if (file
->start_time
== AV_NOPTS_VALUE
)
299 file
->start_time
= !fileno
? 0 :
300 cat
->files
[fileno
- 1].start_time
+
301 cat
->files
[fileno
- 1].duration
;
302 if ((ret
= match_streams(avf
)) < 0)
307 static int concat_read_close(AVFormatContext
*avf
)
309 ConcatContext
*cat
= avf
->priv_data
;
313 avformat_close_input(&cat
->avf
);
314 for (i
= 0; i
< cat
->nb_files
; i
++) {
315 av_freep(&cat
->files
[i
].url
);
316 av_freep(&cat
->files
[i
].streams
);
318 av_freep(&cat
->files
);
322 static int concat_read_header(AVFormatContext
*avf
)
324 ConcatContext
*cat
= avf
->priv_data
;
326 uint8_t *cursor
, *keyword
;
327 int ret
, line
= 0, i
;
328 unsigned nb_files_alloc
= 0;
329 ConcatFile
*file
= NULL
;
333 if ((ret
= ff_get_line(avf
->pb
, buf
, sizeof(buf
))) <= 0)
337 keyword
= get_keyword(&cursor
);
338 if (!*keyword
|| *keyword
== '#')
341 if (!strcmp(keyword
, "file")) {
342 char *filename
= av_get_token((const char **)&cursor
, SPACE_CHARS
);
344 av_log(avf
, AV_LOG_ERROR
, "Line %d: filename required\n", line
);
345 FAIL(AVERROR_INVALIDDATA
);
347 if ((ret
= add_file(avf
, filename
, &file
, &nb_files_alloc
)) < 0)
349 } else if (!strcmp(keyword
, "duration")) {
350 char *dur_str
= get_keyword(&cursor
);
353 av_log(avf
, AV_LOG_ERROR
, "Line %d: duration without file\n",
355 FAIL(AVERROR_INVALIDDATA
);
357 if ((ret
= av_parse_time(&dur
, dur_str
, 1)) < 0) {
358 av_log(avf
, AV_LOG_ERROR
, "Line %d: invalid duration '%s'\n",
362 file
->duration
= dur
;
363 } else if (!strcmp(keyword
, "stream")) {
364 if (!avformat_new_stream(avf
, NULL
))
365 FAIL(AVERROR(ENOMEM
));
366 } else if (!strcmp(keyword
, "exact_stream_id")) {
367 if (!avf
->nb_streams
) {
368 av_log(avf
, AV_LOG_ERROR
, "Line %d: exact_stream_id without stream\n",
370 FAIL(AVERROR_INVALIDDATA
);
372 avf
->streams
[avf
->nb_streams
- 1]->id
=
373 strtol(get_keyword(&cursor
), NULL
, 0);
374 } else if (!strcmp(keyword
, "ffconcat")) {
375 char *ver_kw
= get_keyword(&cursor
);
376 char *ver_val
= get_keyword(&cursor
);
377 if (strcmp(ver_kw
, "version") || strcmp(ver_val
, "1.0")) {
378 av_log(avf
, AV_LOG_ERROR
, "Line %d: invalid version\n", line
);
379 FAIL(AVERROR_INVALIDDATA
);
384 av_log(avf
, AV_LOG_ERROR
, "Line %d: unknown keyword '%s'\n",
386 FAIL(AVERROR_INVALIDDATA
);
392 FAIL(AVERROR_INVALIDDATA
);
394 for (i
= 0; i
< cat
->nb_files
; i
++) {
395 if (cat
->files
[i
].start_time
== AV_NOPTS_VALUE
)
396 cat
->files
[i
].start_time
= time
;
398 time
= cat
->files
[i
].start_time
;
399 if (cat
->files
[i
].duration
== AV_NOPTS_VALUE
)
401 time
+= cat
->files
[i
].duration
;
403 if (i
== cat
->nb_files
) {
404 avf
->duration
= time
;
408 cat
->stream_match_mode
= avf
->nb_streams
? MATCH_EXACT_ID
:
410 if ((ret
= open_file(avf
, 0)) < 0)
415 concat_read_close(avf
);
419 static int open_next_file(AVFormatContext
*avf
)
421 ConcatContext
*cat
= avf
->priv_data
;
422 unsigned fileno
= cat
->cur_file
- cat
->files
;
424 if (cat
->cur_file
->duration
== AV_NOPTS_VALUE
)
425 cat
->cur_file
->duration
= cat
->avf
->duration
;
427 if (++fileno
>= cat
->nb_files
)
429 return open_file(avf
, fileno
);
432 static int filter_packet(AVFormatContext
*avf
, ConcatStream
*cs
, AVPacket
*pkt
)
434 AVStream
*st
= avf
->streams
[cs
->out_stream_index
];
435 AVBitStreamFilterContext
*bsf
;
439 av_assert0(cs
->out_stream_index
>= 0);
440 for (bsf
= cs
->bsf
; bsf
; bsf
= bsf
->next
) {
442 ret
= av_bitstream_filter_filter(bsf
, st
->codec
, NULL
,
443 &pkt2
.data
, &pkt2
.size
,
444 pkt
->data
, pkt
->size
,
445 !!(pkt
->flags
& AV_PKT_FLAG_KEY
));
447 av_packet_unref(pkt
);
450 av_assert0(pkt2
.buf
);
451 if (ret
== 0 && pkt2
.data
!= pkt
->data
) {
452 if ((ret
= av_copy_packet(&pkt2
, pkt
)) < 0) {
460 pkt2
.buf
= av_buffer_create(pkt2
.data
, pkt2
.size
,
461 av_buffer_default_free
, NULL
, 0);
464 return AVERROR(ENOMEM
);
472 static int concat_read_packet(AVFormatContext
*avf
, AVPacket
*pkt
)
474 ConcatContext
*cat
= avf
->priv_data
;
480 ret
= av_read_frame(cat
->avf
, pkt
);
481 if (ret
== AVERROR_EOF
) {
482 if ((ret
= open_next_file(avf
)) < 0)
488 if ((ret
= match_streams(avf
)) < 0) {
489 av_packet_unref(pkt
);
492 cs
= &cat
->cur_file
->streams
[pkt
->stream_index
];
493 if (cs
->out_stream_index
< 0) {
494 av_packet_unref(pkt
);
497 pkt
->stream_index
= cs
->out_stream_index
;
500 if ((ret
= filter_packet(avf
, cs
, pkt
)))
503 delta
= av_rescale_q(cat
->cur_file
->start_time
- cat
->avf
->start_time
,
505 cat
->avf
->streams
[pkt
->stream_index
]->time_base
);
506 if (pkt
->pts
!= AV_NOPTS_VALUE
)
508 if (pkt
->dts
!= AV_NOPTS_VALUE
)
513 static void rescale_interval(AVRational tb_in
, AVRational tb_out
,
514 int64_t *min_ts
, int64_t *ts
, int64_t *max_ts
)
516 *ts
= av_rescale_q (* ts
, tb_in
, tb_out
);
517 *min_ts
= av_rescale_q_rnd(*min_ts
, tb_in
, tb_out
,
518 AV_ROUND_UP
| AV_ROUND_PASS_MINMAX
);
519 *max_ts
= av_rescale_q_rnd(*max_ts
, tb_in
, tb_out
,
520 AV_ROUND_DOWN
| AV_ROUND_PASS_MINMAX
);
523 static int try_seek(AVFormatContext
*avf
, int stream
,
524 int64_t min_ts
, int64_t ts
, int64_t max_ts
, int flags
)
526 ConcatContext
*cat
= avf
->priv_data
;
527 int64_t t0
= cat
->cur_file
->start_time
- cat
->avf
->start_time
;
530 min_ts
= min_ts
== INT64_MIN
? INT64_MIN
: min_ts
- t0
;
531 max_ts
= max_ts
== INT64_MAX
? INT64_MAX
: max_ts
- t0
;
533 if (stream
>= cat
->avf
->nb_streams
)
535 rescale_interval(AV_TIME_BASE_Q
, cat
->avf
->streams
[stream
]->time_base
,
536 &min_ts
, &ts
, &max_ts
);
538 return avformat_seek_file(cat
->avf
, stream
, min_ts
, ts
, max_ts
, flags
);
541 static int real_seek(AVFormatContext
*avf
, int stream
,
542 int64_t min_ts
, int64_t ts
, int64_t max_ts
, int flags
)
544 ConcatContext
*cat
= avf
->priv_data
;
545 int ret
, left
, right
;
548 if (stream
>= avf
->nb_streams
)
549 return AVERROR(EINVAL
);
550 rescale_interval(avf
->streams
[stream
]->time_base
, AV_TIME_BASE_Q
,
551 &min_ts
, &ts
, &max_ts
);
555 right
= cat
->nb_files
;
556 while (right
- left
> 1) {
557 int mid
= (left
+ right
) / 2;
558 if (ts
< cat
->files
[mid
].start_time
)
564 if ((ret
= open_file(avf
, left
)) < 0)
567 ret
= try_seek(avf
, stream
, min_ts
, ts
, max_ts
, flags
);
569 left
< cat
->nb_files
- 1 &&
570 cat
->files
[left
+ 1].start_time
< max_ts
) {
571 if ((ret
= open_file(avf
, left
+ 1)) < 0)
573 ret
= try_seek(avf
, stream
, min_ts
, ts
, max_ts
, flags
);
578 static int concat_seek(AVFormatContext
*avf
, int stream
,
579 int64_t min_ts
, int64_t ts
, int64_t max_ts
, int flags
)
581 ConcatContext
*cat
= avf
->priv_data
;
582 ConcatFile
*cur_file_saved
= cat
->cur_file
;
583 AVFormatContext
*cur_avf_saved
= cat
->avf
;
587 return AVERROR(ESPIPE
); /* XXX: can we use it? */
588 if (flags
& (AVSEEK_FLAG_BYTE
| AVSEEK_FLAG_FRAME
))
589 return AVERROR(ENOSYS
);
591 if ((ret
= real_seek(avf
, stream
, min_ts
, ts
, max_ts
, flags
)) < 0) {
593 avformat_close_input(&cat
->avf
);
594 cat
->avf
= cur_avf_saved
;
595 cat
->cur_file
= cur_file_saved
;
597 avformat_close_input(&cur_avf_saved
);
602 #define OFFSET(x) offsetof(ConcatContext, x)
603 #define DEC AV_OPT_FLAG_DECODING_PARAM
605 static const AVOption options
[] = {
606 { "safe", "enable safe mode",
607 OFFSET(safe
), AV_OPT_TYPE_INT
, {.i64
= -1}, -1, 1, DEC
},
608 { "auto_convert", "automatically convert bitstream format",
609 OFFSET(auto_convert
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, 1, DEC
},
613 static const AVClass concat_class
= {
614 .class_name
= "concat demuxer",
615 .item_name
= av_default_item_name
,
617 .version
= LIBAVUTIL_VERSION_INT
,
621 AVInputFormat ff_concat_demuxer
= {
623 .long_name
= NULL_IF_CONFIG_SMALL("Virtual concatenation script"),
624 .priv_data_size
= sizeof(ConcatContext
),
625 .read_probe
= concat_probe
,
626 .read_header
= concat_read_header
,
627 .read_packet
= concat_read_packet
,
628 .read_close
= concat_read_close
,
629 .read_seek2
= concat_seek
,
630 .priv_class
= &concat_class
,