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"
26 #include "libavutil/timestamp.h"
31 typedef enum ConcatMatchMode
{
36 typedef struct ConcatStream
{
37 AVBitStreamFilterContext
*bsf
;
45 ConcatStream
*streams
;
57 ConcatMatchMode stream_match_mode
;
58 unsigned auto_convert
;
61 static int concat_probe(AVProbeData
*probe
)
63 return memcmp(probe
->buf
, "ffconcat version 1.0", 20) ?
64 0 : AVPROBE_SCORE_MAX
;
67 static char *get_keyword(uint8_t **cursor
)
69 char *ret
= *cursor
+= strspn(*cursor
, SPACE_CHARS
);
70 *cursor
+= strcspn(*cursor
, SPACE_CHARS
);
73 *cursor
+= strspn(*cursor
, SPACE_CHARS
);
78 static int safe_filename(const char *f
)
80 const char *start
= f
;
84 if (!((unsigned)((*f
| 32) - 'a') < 26 ||
85 (unsigned)(*f
- '0') < 10 || *f
== '_' || *f
== '-')) {
97 #define FAIL(retcode) do { ret = (retcode); goto fail; } while(0)
99 static int add_file(AVFormatContext
*avf
, char *filename
, ConcatFile
**rfile
,
100 unsigned *nb_files_alloc
)
102 ConcatContext
*cat
= avf
->priv_data
;
106 size_t url_len
, proto_len
;
109 if (cat
->safe
> 0 && !safe_filename(filename
)) {
110 av_log(avf
, AV_LOG_ERROR
, "Unsafe file name '%s'\n", filename
);
111 FAIL(AVERROR(EPERM
));
114 proto
= avio_find_protocol_name(filename
);
115 proto_len
= proto
? strlen(proto
) : 0;
116 if (!memcmp(filename
, proto
, proto_len
) &&
117 (filename
[proto_len
] == ':' || filename
[proto_len
] == ',')) {
121 url_len
= strlen(avf
->filename
) + strlen(filename
) + 16;
122 if (!(url
= av_malloc(url_len
)))
123 FAIL(AVERROR(ENOMEM
));
124 ff_make_absolute_url(url
, url_len
, avf
->filename
, filename
);
128 if (cat
->nb_files
>= *nb_files_alloc
) {
129 size_t n
= FFMAX(*nb_files_alloc
* 2, 16);
130 ConcatFile
*new_files
;
131 if (n
<= cat
->nb_files
|| n
> SIZE_MAX
/ sizeof(*cat
->files
) ||
132 !(new_files
= av_realloc(cat
->files
, n
* sizeof(*cat
->files
))))
133 FAIL(AVERROR(ENOMEM
));
134 cat
->files
= new_files
;
138 file
= &cat
->files
[cat
->nb_files
++];
139 memset(file
, 0, sizeof(*file
));
143 file
->start_time
= AV_NOPTS_VALUE
;
144 file
->duration
= AV_NOPTS_VALUE
;
154 static int copy_stream_props(AVStream
*st
, AVStream
*source_st
)
158 if (st
->codec
->codec_id
|| !source_st
->codec
->codec_id
) {
159 if (st
->codec
->extradata_size
< source_st
->codec
->extradata_size
) {
160 ret
= ff_alloc_extradata(st
->codec
,
161 source_st
->codec
->extradata_size
);
165 memcpy(st
->codec
->extradata
, source_st
->codec
->extradata
,
166 source_st
->codec
->extradata_size
);
169 if ((ret
= avcodec_copy_context(st
->codec
, source_st
->codec
)) < 0)
171 st
->r_frame_rate
= source_st
->r_frame_rate
;
172 st
->avg_frame_rate
= source_st
->avg_frame_rate
;
173 st
->time_base
= source_st
->time_base
;
174 st
->sample_aspect_ratio
= source_st
->sample_aspect_ratio
;
178 static int detect_stream_specific(AVFormatContext
*avf
, int idx
)
180 ConcatContext
*cat
= avf
->priv_data
;
181 AVStream
*st
= cat
->avf
->streams
[idx
];
182 ConcatStream
*cs
= &cat
->cur_file
->streams
[idx
];
183 AVBitStreamFilterContext
*bsf
;
185 if (cat
->auto_convert
&& st
->codec
->codec_id
== AV_CODEC_ID_H264
&&
186 (st
->codec
->extradata_size
< 4 || AV_RB32(st
->codec
->extradata
) != 1)) {
187 av_log(cat
->avf
, AV_LOG_INFO
,
188 "Auto-inserting h264_mp4toannexb bitstream filter\n");
189 if (!(bsf
= av_bitstream_filter_init("h264_mp4toannexb"))) {
190 av_log(avf
, AV_LOG_ERROR
, "h264_mp4toannexb bitstream filter "
191 "required for H.264 streams\n");
192 return AVERROR_BSF_NOT_FOUND
;
199 static int match_streams_one_to_one(AVFormatContext
*avf
)
201 ConcatContext
*cat
= avf
->priv_data
;
205 for (i
= cat
->cur_file
->nb_streams
; i
< cat
->avf
->nb_streams
; i
++) {
206 if (i
< avf
->nb_streams
) {
207 st
= avf
->streams
[i
];
209 if (!(st
= avformat_new_stream(avf
, NULL
)))
210 return AVERROR(ENOMEM
);
212 if ((ret
= copy_stream_props(st
, cat
->avf
->streams
[i
])) < 0)
214 cat
->cur_file
->streams
[i
].out_stream_index
= i
;
219 static int match_streams_exact_id(AVFormatContext
*avf
)
221 ConcatContext
*cat
= avf
->priv_data
;
225 for (i
= cat
->cur_file
->nb_streams
; i
< cat
->avf
->nb_streams
; i
++) {
226 st
= cat
->avf
->streams
[i
];
227 for (j
= 0; j
< avf
->nb_streams
; j
++) {
228 if (avf
->streams
[j
]->id
== st
->id
) {
229 av_log(avf
, AV_LOG_VERBOSE
,
230 "Match slave stream #%d with stream #%d id 0x%x\n",
232 if ((ret
= copy_stream_props(avf
->streams
[j
], st
)) < 0)
234 cat
->cur_file
->streams
[i
].out_stream_index
= j
;
241 static int match_streams(AVFormatContext
*avf
)
243 ConcatContext
*cat
= avf
->priv_data
;
247 if (cat
->cur_file
->nb_streams
>= cat
->avf
->nb_streams
)
249 map
= av_realloc(cat
->cur_file
->streams
,
250 cat
->avf
->nb_streams
* sizeof(*map
));
252 return AVERROR(ENOMEM
);
253 cat
->cur_file
->streams
= map
;
254 memset(map
+ cat
->cur_file
->nb_streams
, 0,
255 (cat
->avf
->nb_streams
- cat
->cur_file
->nb_streams
) * sizeof(*map
));
257 for (i
= cat
->cur_file
->nb_streams
; i
< cat
->avf
->nb_streams
; i
++)
258 map
[i
].out_stream_index
= -1;
259 switch (cat
->stream_match_mode
) {
260 case MATCH_ONE_TO_ONE
:
261 ret
= match_streams_one_to_one(avf
);
264 ret
= match_streams_exact_id(avf
);
271 for (i
= cat
->cur_file
->nb_streams
; i
< cat
->avf
->nb_streams
; i
++)
272 if ((ret
= detect_stream_specific(avf
, i
)) < 0)
274 cat
->cur_file
->nb_streams
= cat
->avf
->nb_streams
;
278 static int open_file(AVFormatContext
*avf
, unsigned fileno
)
280 ConcatContext
*cat
= avf
->priv_data
;
281 ConcatFile
*file
= &cat
->files
[fileno
];
285 avformat_close_input(&cat
->avf
);
287 cat
->avf
= avformat_alloc_context();
289 return AVERROR(ENOMEM
);
291 cat
->avf
->interrupt_callback
= avf
->interrupt_callback
;
293 if ((ret
= ff_copy_whitelists(cat
->avf
, avf
)) < 0)
296 if ((ret
= avformat_open_input(&cat
->avf
, file
->url
, NULL
, NULL
)) < 0 ||
297 (ret
= avformat_find_stream_info(cat
->avf
, NULL
)) < 0) {
298 av_log(avf
, AV_LOG_ERROR
, "Impossible to open '%s'\n", file
->url
);
299 avformat_close_input(&cat
->avf
);
302 cat
->cur_file
= file
;
303 if (file
->start_time
== AV_NOPTS_VALUE
)
304 file
->start_time
= !fileno
? 0 :
305 cat
->files
[fileno
- 1].start_time
+
306 cat
->files
[fileno
- 1].duration
;
307 if ((ret
= match_streams(avf
)) < 0)
312 static int concat_read_close(AVFormatContext
*avf
)
314 ConcatContext
*cat
= avf
->priv_data
;
318 avformat_close_input(&cat
->avf
);
319 for (i
= 0; i
< cat
->nb_files
; i
++) {
320 av_freep(&cat
->files
[i
].url
);
321 av_freep(&cat
->files
[i
].streams
);
323 av_freep(&cat
->files
);
327 static int concat_read_header(AVFormatContext
*avf
)
329 ConcatContext
*cat
= avf
->priv_data
;
331 uint8_t *cursor
, *keyword
;
332 int ret
, line
= 0, i
;
333 unsigned nb_files_alloc
= 0;
334 ConcatFile
*file
= NULL
;
338 if ((ret
= ff_get_line(avf
->pb
, buf
, sizeof(buf
))) <= 0)
342 keyword
= get_keyword(&cursor
);
343 if (!*keyword
|| *keyword
== '#')
346 if (!strcmp(keyword
, "file")) {
347 char *filename
= av_get_token((const char **)&cursor
, SPACE_CHARS
);
349 av_log(avf
, AV_LOG_ERROR
, "Line %d: filename required\n", line
);
350 FAIL(AVERROR_INVALIDDATA
);
352 if ((ret
= add_file(avf
, filename
, &file
, &nb_files_alloc
)) < 0)
354 } else if (!strcmp(keyword
, "duration")) {
355 char *dur_str
= get_keyword(&cursor
);
358 av_log(avf
, AV_LOG_ERROR
, "Line %d: duration without file\n",
360 FAIL(AVERROR_INVALIDDATA
);
362 if ((ret
= av_parse_time(&dur
, dur_str
, 1)) < 0) {
363 av_log(avf
, AV_LOG_ERROR
, "Line %d: invalid duration '%s'\n",
367 file
->duration
= dur
;
368 } else if (!strcmp(keyword
, "stream")) {
369 if (!avformat_new_stream(avf
, NULL
))
370 FAIL(AVERROR(ENOMEM
));
371 } else if (!strcmp(keyword
, "exact_stream_id")) {
372 if (!avf
->nb_streams
) {
373 av_log(avf
, AV_LOG_ERROR
, "Line %d: exact_stream_id without stream\n",
375 FAIL(AVERROR_INVALIDDATA
);
377 avf
->streams
[avf
->nb_streams
- 1]->id
=
378 strtol(get_keyword(&cursor
), NULL
, 0);
379 } else if (!strcmp(keyword
, "ffconcat")) {
380 char *ver_kw
= get_keyword(&cursor
);
381 char *ver_val
= get_keyword(&cursor
);
382 if (strcmp(ver_kw
, "version") || strcmp(ver_val
, "1.0")) {
383 av_log(avf
, AV_LOG_ERROR
, "Line %d: invalid version\n", line
);
384 FAIL(AVERROR_INVALIDDATA
);
389 av_log(avf
, AV_LOG_ERROR
, "Line %d: unknown keyword '%s'\n",
391 FAIL(AVERROR_INVALIDDATA
);
397 FAIL(AVERROR_INVALIDDATA
);
399 for (i
= 0; i
< cat
->nb_files
; i
++) {
400 if (cat
->files
[i
].start_time
== AV_NOPTS_VALUE
)
401 cat
->files
[i
].start_time
= time
;
403 time
= cat
->files
[i
].start_time
;
404 if (cat
->files
[i
].duration
== AV_NOPTS_VALUE
)
406 time
+= cat
->files
[i
].duration
;
408 if (i
== cat
->nb_files
) {
409 avf
->duration
= time
;
413 cat
->stream_match_mode
= avf
->nb_streams
? MATCH_EXACT_ID
:
415 if ((ret
= open_file(avf
, 0)) < 0)
420 concat_read_close(avf
);
424 static int open_next_file(AVFormatContext
*avf
)
426 ConcatContext
*cat
= avf
->priv_data
;
427 unsigned fileno
= cat
->cur_file
- cat
->files
;
429 if (cat
->cur_file
->duration
== AV_NOPTS_VALUE
)
430 cat
->cur_file
->duration
= cat
->avf
->duration
;
432 if (++fileno
>= cat
->nb_files
)
434 return open_file(avf
, fileno
);
437 static int filter_packet(AVFormatContext
*avf
, ConcatStream
*cs
, AVPacket
*pkt
)
439 AVStream
*st
= avf
->streams
[cs
->out_stream_index
];
440 AVBitStreamFilterContext
*bsf
;
444 av_assert0(cs
->out_stream_index
>= 0);
445 for (bsf
= cs
->bsf
; bsf
; bsf
= bsf
->next
) {
447 ret
= av_bitstream_filter_filter(bsf
, st
->codec
, NULL
,
448 &pkt2
.data
, &pkt2
.size
,
449 pkt
->data
, pkt
->size
,
450 !!(pkt
->flags
& AV_PKT_FLAG_KEY
));
452 av_packet_unref(pkt
);
455 av_assert0(pkt2
.buf
);
456 if (ret
== 0 && pkt2
.data
!= pkt
->data
) {
457 if ((ret
= av_copy_packet(&pkt2
, pkt
)) < 0) {
465 pkt2
.buf
= av_buffer_create(pkt2
.data
, pkt2
.size
,
466 av_buffer_default_free
, NULL
, 0);
469 return AVERROR(ENOMEM
);
477 static int concat_read_packet(AVFormatContext
*avf
, AVPacket
*pkt
)
479 ConcatContext
*cat
= avf
->priv_data
;
486 ret
= av_read_frame(cat
->avf
, pkt
);
487 if (ret
== AVERROR_EOF
) {
488 if ((ret
= open_next_file(avf
)) < 0)
494 if ((ret
= match_streams(avf
)) < 0) {
495 av_packet_unref(pkt
);
498 cs
= &cat
->cur_file
->streams
[pkt
->stream_index
];
499 if (cs
->out_stream_index
< 0) {
500 av_packet_unref(pkt
);
503 pkt
->stream_index
= cs
->out_stream_index
;
506 if ((ret
= filter_packet(avf
, cs
, pkt
)))
509 st
= cat
->avf
->streams
[pkt
->stream_index
];
510 av_log(avf
, AV_LOG_DEBUG
, "file:%d stream:%d pts:%s pts_time:%s dts:%s dts_time:%s",
511 (unsigned)(cat
->cur_file
- cat
->files
), pkt
->stream_index
,
512 av_ts2str(pkt
->pts
), av_ts2timestr(pkt
->pts
, &st
->time_base
),
513 av_ts2str(pkt
->dts
), av_ts2timestr(pkt
->dts
, &st
->time_base
));
515 delta
= av_rescale_q(cat
->cur_file
->start_time
- cat
->avf
->start_time
,
517 cat
->avf
->streams
[pkt
->stream_index
]->time_base
);
518 if (pkt
->pts
!= AV_NOPTS_VALUE
)
520 if (pkt
->dts
!= AV_NOPTS_VALUE
)
522 av_log(avf
, AV_LOG_DEBUG
, " -> pts:%s pts_time:%s dts:%s dts_time:%s\n",
523 av_ts2str(pkt
->pts
), av_ts2timestr(pkt
->pts
, &st
->time_base
),
524 av_ts2str(pkt
->dts
), av_ts2timestr(pkt
->dts
, &st
->time_base
));
528 static void rescale_interval(AVRational tb_in
, AVRational tb_out
,
529 int64_t *min_ts
, int64_t *ts
, int64_t *max_ts
)
531 *ts
= av_rescale_q (* ts
, tb_in
, tb_out
);
532 *min_ts
= av_rescale_q_rnd(*min_ts
, tb_in
, tb_out
,
533 AV_ROUND_UP
| AV_ROUND_PASS_MINMAX
);
534 *max_ts
= av_rescale_q_rnd(*max_ts
, tb_in
, tb_out
,
535 AV_ROUND_DOWN
| AV_ROUND_PASS_MINMAX
);
538 static int try_seek(AVFormatContext
*avf
, int stream
,
539 int64_t min_ts
, int64_t ts
, int64_t max_ts
, int flags
)
541 ConcatContext
*cat
= avf
->priv_data
;
542 int64_t t0
= cat
->cur_file
->start_time
- cat
->avf
->start_time
;
545 min_ts
= min_ts
== INT64_MIN
? INT64_MIN
: min_ts
- t0
;
546 max_ts
= max_ts
== INT64_MAX
? INT64_MAX
: max_ts
- t0
;
548 if (stream
>= cat
->avf
->nb_streams
)
550 rescale_interval(AV_TIME_BASE_Q
, cat
->avf
->streams
[stream
]->time_base
,
551 &min_ts
, &ts
, &max_ts
);
553 return avformat_seek_file(cat
->avf
, stream
, min_ts
, ts
, max_ts
, flags
);
556 static int real_seek(AVFormatContext
*avf
, int stream
,
557 int64_t min_ts
, int64_t ts
, int64_t max_ts
, int flags
)
559 ConcatContext
*cat
= avf
->priv_data
;
560 int ret
, left
, right
;
563 if (stream
>= avf
->nb_streams
)
564 return AVERROR(EINVAL
);
565 rescale_interval(avf
->streams
[stream
]->time_base
, AV_TIME_BASE_Q
,
566 &min_ts
, &ts
, &max_ts
);
570 right
= cat
->nb_files
;
571 while (right
- left
> 1) {
572 int mid
= (left
+ right
) / 2;
573 if (ts
< cat
->files
[mid
].start_time
)
579 if ((ret
= open_file(avf
, left
)) < 0)
582 ret
= try_seek(avf
, stream
, min_ts
, ts
, max_ts
, flags
);
584 left
< cat
->nb_files
- 1 &&
585 cat
->files
[left
+ 1].start_time
< max_ts
) {
586 if ((ret
= open_file(avf
, left
+ 1)) < 0)
588 ret
= try_seek(avf
, stream
, min_ts
, ts
, max_ts
, flags
);
593 static int concat_seek(AVFormatContext
*avf
, int stream
,
594 int64_t min_ts
, int64_t ts
, int64_t max_ts
, int flags
)
596 ConcatContext
*cat
= avf
->priv_data
;
597 ConcatFile
*cur_file_saved
= cat
->cur_file
;
598 AVFormatContext
*cur_avf_saved
= cat
->avf
;
602 return AVERROR(ESPIPE
); /* XXX: can we use it? */
603 if (flags
& (AVSEEK_FLAG_BYTE
| AVSEEK_FLAG_FRAME
))
604 return AVERROR(ENOSYS
);
606 if ((ret
= real_seek(avf
, stream
, min_ts
, ts
, max_ts
, flags
)) < 0) {
608 avformat_close_input(&cat
->avf
);
609 cat
->avf
= cur_avf_saved
;
610 cat
->cur_file
= cur_file_saved
;
612 avformat_close_input(&cur_avf_saved
);
617 #define OFFSET(x) offsetof(ConcatContext, x)
618 #define DEC AV_OPT_FLAG_DECODING_PARAM
620 static const AVOption options
[] = {
621 { "safe", "enable safe mode",
622 OFFSET(safe
), AV_OPT_TYPE_INT
, {.i64
= -1}, -1, 1, DEC
},
623 { "auto_convert", "automatically convert bitstream format",
624 OFFSET(auto_convert
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, 1, DEC
},
628 static const AVClass concat_class
= {
629 .class_name
= "concat demuxer",
630 .item_name
= av_default_item_name
,
632 .version
= LIBAVUTIL_VERSION_INT
,
636 AVInputFormat ff_concat_demuxer
= {
638 .long_name
= NULL_IF_CONFIG_SMALL("Virtual concatenation script"),
639 .priv_data_size
= sizeof(ConcatContext
),
640 .read_probe
= concat_probe
,
641 .read_header
= concat_read_header
,
642 .read_packet
= concat_read_packet
,
643 .read_close
= concat_read_close
,
644 .read_seek2
= concat_seek
,
645 .priv_class
= &concat_class
,