1 /*
2 * Copyright (c) 2012 Nicolas George
3 *
4 * This file is part of FFmpeg.
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "libavutil/avstring.h"
22 #include "libavutil/avassert.h"
23 #include "libavutil/bprint.h"
24 #include "libavutil/intreadwrite.h"
25 #include "libavutil/opt.h"
26 #include "libavutil/parseutils.h"
27 #include "libavutil/timestamp.h"
28 #include "libavcodec/bsf.h"
29 #include "avformat.h"
30 #include "avio_internal.h"
31 #include "demux.h"
32 #include "internal.h"
33 #include "url.h"
34
35 typedef enum ConcatMatchMode {
36 MATCH_ONE_TO_ONE,
37 MATCH_EXACT_ID,
38 } ConcatMatchMode;
39
40 typedef struct ConcatStream {
41 AVBSFContext *bsf;
42 int out_stream_index;
43 } ConcatStream;
44
45 typedef struct {
46 char *url;
47 int64_t start_time;
48 int64_t file_start_time;
49 int64_t file_inpoint;
50 int64_t duration;
51 int64_t user_duration;
52 int64_t next_dts;
53 ConcatStream *streams;
54 int64_t inpoint;
55 int64_t outpoint;
56 AVDictionary *metadata;
57 AVDictionary *options;
58 int nb_streams;
59 } ConcatFile;
60
61 typedef struct {
62 AVClass *class;
63 ConcatFile *files;
64 ConcatFile *cur_file;
65 unsigned nb_files;
66 AVFormatContext *avf;
67 int safe;
68 int seekable;
69 int eof;
70 ConcatMatchMode stream_match_mode;
71 unsigned auto_convert;
72 int segment_time_metadata;
73 } ConcatContext;
74
concat_probe(const AVProbeData * probe)75 static int concat_probe(const AVProbeData *probe)
76 {
77 return memcmp(probe->buf, "ffconcat version 1.0", 20) ?
78 0 : AVPROBE_SCORE_MAX;
79 }
80
get_keyword(uint8_t ** cursor)81 static char *get_keyword(uint8_t **cursor)
82 {
83 char *ret = *cursor += strspn(*cursor, SPACE_CHARS);
84 *cursor += strcspn(*cursor, SPACE_CHARS);
85 if (**cursor) {
86 *((*cursor)++) = 0;
87 *cursor += strspn(*cursor, SPACE_CHARS);
88 }
89 return ret;
90 }
91
safe_filename(const char * f)92 static int safe_filename(const char *f)
93 {
94 const char *start = f;
95
96 for (; *f; f++) {
97 /* A-Za-z0-9_- */
98 if (!((unsigned)((*f | 32) - 'a') < 26 ||
99 (unsigned)(*f - '0') < 10 || *f == '_' || *f == '-')) {
100 if (f == start)
101 return 0;
102 else if (*f == '/')
103 start = f + 1;
104 else if (*f != '.')
105 return 0;
106 }
107 }
108 return 1;
109 }
110
111 #define FAIL(retcode) do { ret = (retcode); goto fail; } while(0)
112
add_file(AVFormatContext * avf,char * filename,ConcatFile ** rfile,unsigned * nb_files_alloc)113 static int add_file(AVFormatContext *avf, char *filename, ConcatFile **rfile,
114 unsigned *nb_files_alloc)
115 {
116 ConcatContext *cat = avf->priv_data;
117 ConcatFile *file;
118 char *url = NULL;
119 const char *proto;
120 const char *ptr;
121 size_t url_len;
122 int ret;
123
124 if (cat->safe && !safe_filename(filename)) {
125 av_log(avf, AV_LOG_ERROR, "Unsafe file name '%s'\n", filename);
126 FAIL(AVERROR(EPERM));
127 }
128
129 proto = avio_find_protocol_name(filename);
130 if (proto && av_strstart(filename, proto, &ptr) &&
131 (*ptr == ':' || *ptr == ',')) {
132 url = filename;
133 filename = NULL;
134 } else {
135 url_len = strlen(avf->url) + strlen(filename) + 16;
136 if (!(url = av_malloc(url_len)))
137 FAIL(AVERROR(ENOMEM));
138 ff_make_absolute_url(url, url_len, avf->url, filename);
139 av_freep(&filename);
140 }
141
142 if (cat->nb_files >= *nb_files_alloc) {
143 size_t n = FFMAX(*nb_files_alloc * 2, 16);
144 ConcatFile *new_files;
145 if (n <= cat->nb_files || n > SIZE_MAX / sizeof(*cat->files) ||
146 !(new_files = av_realloc(cat->files, n * sizeof(*cat->files))))
147 FAIL(AVERROR(ENOMEM));
148 cat->files = new_files;
149 *nb_files_alloc = n;
150 }
151
152 file = &cat->files[cat->nb_files++];
153 memset(file, 0, sizeof(*file));
154 *rfile = file;
155
156 file->url = url;
157 file->start_time = AV_NOPTS_VALUE;
158 file->duration = AV_NOPTS_VALUE;
159 file->next_dts = AV_NOPTS_VALUE;
160 file->inpoint = AV_NOPTS_VALUE;
161 file->outpoint = AV_NOPTS_VALUE;
162 file->user_duration = AV_NOPTS_VALUE;
163
164 return 0;
165
166 fail:
167 av_free(url);
168 av_free(filename);
169 return ret;
170 }
171
copy_stream_props(AVStream * st,AVStream * source_st)172 static int copy_stream_props(AVStream *st, AVStream *source_st)
173 {
174 int ret;
175
176 if (st->codecpar->codec_id || !source_st->codecpar->codec_id) {
177 if (st->codecpar->extradata_size < source_st->codecpar->extradata_size) {
178 ret = ff_alloc_extradata(st->codecpar,
179 source_st->codecpar->extradata_size);
180 if (ret < 0)
181 return ret;
182 }
183 memcpy(st->codecpar->extradata, source_st->codecpar->extradata,
184 source_st->codecpar->extradata_size);
185 return 0;
186 }
187 if ((ret = avcodec_parameters_copy(st->codecpar, source_st->codecpar)) < 0)
188 return ret;
189 st->r_frame_rate = source_st->r_frame_rate;
190 st->avg_frame_rate = source_st->avg_frame_rate;
191 st->sample_aspect_ratio = source_st->sample_aspect_ratio;
192 avpriv_set_pts_info(st, 64, source_st->time_base.num, source_st->time_base.den);
193
194 av_dict_copy(&st->metadata, source_st->metadata, 0);
195 ff_stream_side_data_copy(st, source_st);
196 return 0;
197 }
198
detect_stream_specific(AVFormatContext * avf,int idx)199 static int detect_stream_specific(AVFormatContext *avf, int idx)
200 {
201 ConcatContext *cat = avf->priv_data;
202 AVStream *st = cat->avf->streams[idx];
203 ConcatStream *cs = &cat->cur_file->streams[idx];
204 const AVBitStreamFilter *filter;
205 AVBSFContext *bsf;
206 int ret;
207
208 if (cat->auto_convert && st->codecpar->codec_id == AV_CODEC_ID_H264) {
209 if (!st->codecpar->extradata_size ||
210 (st->codecpar->extradata_size >= 3 && AV_RB24(st->codecpar->extradata) == 1) ||
211 (st->codecpar->extradata_size >= 4 && AV_RB32(st->codecpar->extradata) == 1))
212 return 0;
213 av_log(cat->avf, AV_LOG_INFO,
214 "Auto-inserting h264_mp4toannexb bitstream filter\n");
215 filter = av_bsf_get_by_name("h264_mp4toannexb");
216 if (!filter) {
217 av_log(avf, AV_LOG_ERROR, "h264_mp4toannexb bitstream filter "
218 "required for H.264 streams\n");
219 return AVERROR_BSF_NOT_FOUND;
220 }
221 ret = av_bsf_alloc(filter, &bsf);
222 if (ret < 0)
223 return ret;
224 cs->bsf = bsf;
225
226 ret = avcodec_parameters_copy(bsf->par_in, st->codecpar);
227 if (ret < 0)
228 return ret;
229
230 ret = av_bsf_init(bsf);
231 if (ret < 0)
232 return ret;
233
234 ret = avcodec_parameters_copy(st->codecpar, bsf->par_out);
235 if (ret < 0)
236 return ret;
237 }
238 return 0;
239 }
240
match_streams_one_to_one(AVFormatContext * avf)241 static int match_streams_one_to_one(AVFormatContext *avf)
242 {
243 ConcatContext *cat = avf->priv_data;
244 AVStream *st;
245 int i, ret;
246
247 for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) {
248 if (i < avf->nb_streams) {
249 st = avf->streams[i];
250 } else {
251 if (!(st = avformat_new_stream(avf, NULL)))
252 return AVERROR(ENOMEM);
253 }
254 if ((ret = copy_stream_props(st, cat->avf->streams[i])) < 0)
255 return ret;
256 cat->cur_file->streams[i].out_stream_index = i;
257 }
258 return 0;
259 }
260
match_streams_exact_id(AVFormatContext * avf)261 static int match_streams_exact_id(AVFormatContext *avf)
262 {
263 ConcatContext *cat = avf->priv_data;
264 AVStream *st;
265 int i, j, ret;
266
267 for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) {
268 st = cat->avf->streams[i];
269 for (j = 0; j < avf->nb_streams; j++) {
270 if (avf->streams[j]->id == st->id) {
271 av_log(avf, AV_LOG_VERBOSE,
272 "Match slave stream #%d with stream #%d id 0x%x\n",
273 i, j, st->id);
274 if ((ret = copy_stream_props(avf->streams[j], st)) < 0)
275 return ret;
276 cat->cur_file->streams[i].out_stream_index = j;
277 }
278 }
279 }
280 return 0;
281 }
282
match_streams(AVFormatContext * avf)283 static int match_streams(AVFormatContext *avf)
284 {
285 ConcatContext *cat = avf->priv_data;
286 ConcatStream *map;
287 int i, ret;
288
289 if (cat->cur_file->nb_streams >= cat->avf->nb_streams)
290 return 0;
291 map = av_realloc(cat->cur_file->streams,
292 cat->avf->nb_streams * sizeof(*map));
293 if (!map)
294 return AVERROR(ENOMEM);
295 cat->cur_file->streams = map;
296 memset(map + cat->cur_file->nb_streams, 0,
297 (cat->avf->nb_streams - cat->cur_file->nb_streams) * sizeof(*map));
298
299 for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) {
300 map[i].out_stream_index = -1;
301 if ((ret = detect_stream_specific(avf, i)) < 0)
302 return ret;
303 }
304 switch (cat->stream_match_mode) {
305 case MATCH_ONE_TO_ONE:
306 ret = match_streams_one_to_one(avf);
307 break;
308 case MATCH_EXACT_ID:
309 ret = match_streams_exact_id(avf);
310 break;
311 default:
312 ret = AVERROR_BUG;
313 }
314 if (ret < 0)
315 return ret;
316 cat->cur_file->nb_streams = cat->avf->nb_streams;
317 return 0;
318 }
319
get_best_effort_duration(ConcatFile * file,AVFormatContext * avf)320 static int64_t get_best_effort_duration(ConcatFile *file, AVFormatContext *avf)
321 {
322 if (file->user_duration != AV_NOPTS_VALUE)
323 return file->user_duration;
324 if (file->outpoint != AV_NOPTS_VALUE)
325 return file->outpoint - file->file_inpoint;
326 if (avf->duration > 0)
327 return avf->duration - (file->file_inpoint - file->file_start_time);
328 if (file->next_dts != AV_NOPTS_VALUE)
329 return file->next_dts - file->file_inpoint;
330 return AV_NOPTS_VALUE;
331 }
332
open_file(AVFormatContext * avf,unsigned fileno)333 static int open_file(AVFormatContext *avf, unsigned fileno)
334 {
335 ConcatContext *cat = avf->priv_data;
336 ConcatFile *file = &cat->files[fileno];
337 AVDictionary *options = NULL;
338 int ret;
339
340 if (cat->avf)
341 avformat_close_input(&cat->avf);
342
343 cat->avf = avformat_alloc_context();
344 if (!cat->avf)
345 return AVERROR(ENOMEM);
346
347 cat->avf->flags |= avf->flags & ~AVFMT_FLAG_CUSTOM_IO;
348 cat->avf->interrupt_callback = avf->interrupt_callback;
349
350 if ((ret = ff_copy_whiteblacklists(cat->avf, avf)) < 0)
351 return ret;
352
353 ret = av_dict_copy(&options, file->options, 0);
354 if (ret < 0)
355 return ret;
356
357 if ((ret = avformat_open_input(&cat->avf, file->url, NULL, &options)) < 0 ||
358 (ret = avformat_find_stream_info(cat->avf, NULL)) < 0) {
359 av_log(avf, AV_LOG_ERROR, "Impossible to open '%s'\n", file->url);
360 av_dict_free(&options);
361 avformat_close_input(&cat->avf);
362 return ret;
363 }
364 if (options) {
365 av_log(avf, AV_LOG_WARNING, "Unused options for '%s'.\n", file->url);
366 /* TODO log unused options once we have a proper string API */
367 av_dict_free(&options);
368 }
369 cat->cur_file = file;
370 file->start_time = !fileno ? 0 :
371 cat->files[fileno - 1].start_time +
372 cat->files[fileno - 1].duration;
373 file->file_start_time = (cat->avf->start_time == AV_NOPTS_VALUE) ? 0 : cat->avf->start_time;
374 file->file_inpoint = (file->inpoint == AV_NOPTS_VALUE) ? file->file_start_time : file->inpoint;
375 file->duration = get_best_effort_duration(file, cat->avf);
376
377 if (cat->segment_time_metadata) {
378 av_dict_set_int(&file->metadata, "lavf.concatdec.start_time", file->start_time, 0);
379 if (file->duration != AV_NOPTS_VALUE)
380 av_dict_set_int(&file->metadata, "lavf.concatdec.duration", file->duration, 0);
381 }
382
383 if ((ret = match_streams(avf)) < 0)
384 return ret;
385 if (file->inpoint != AV_NOPTS_VALUE) {
386 if ((ret = avformat_seek_file(cat->avf, -1, INT64_MIN, file->inpoint, file->inpoint, 0)) < 0)
387 return ret;
388 }
389 return 0;
390 }
391
concat_read_close(AVFormatContext * avf)392 static int concat_read_close(AVFormatContext *avf)
393 {
394 ConcatContext *cat = avf->priv_data;
395 unsigned i, j;
396
397 for (i = 0; i < cat->nb_files; i++) {
398 av_freep(&cat->files[i].url);
399 for (j = 0; j < cat->files[i].nb_streams; j++) {
400 if (cat->files[i].streams[j].bsf)
401 av_bsf_free(&cat->files[i].streams[j].bsf);
402 }
403 av_freep(&cat->files[i].streams);
404 av_dict_free(&cat->files[i].metadata);
405 av_dict_free(&cat->files[i].options);
406 }
407 if (cat->avf)
408 avformat_close_input(&cat->avf);
409 av_freep(&cat->files);
410 return 0;
411 }
412
413 #define MAX_ARGS 3
414 #define NEEDS_UNSAFE (1 << 0)
415 #define NEEDS_FILE (1 << 1)
416 #define NEEDS_STREAM (1 << 2)
417
418 typedef struct ParseSyntax {
419 const char *keyword;
420 char args[MAX_ARGS];
421 uint8_t flags;
422 } ParseSyntax;
423
424 typedef enum ParseDirective {
425 DIR_FFCONCAT,
426 DIR_FILE,
427 DIR_DURATION,
428 DIR_INPOINT,
429 DIR_OUTPOINT,
430 DIR_FPMETA,
431 DIR_FPMETAS,
432 DIR_OPTION,
433 DIR_STREAM,
434 DIR_EXSID,
435 DIR_STMETA,
436 DIR_STCODEC,
437 DIR_STEDATA,
438 DIR_CHAPTER,
439 } ParseDirective;
440
441 static const ParseSyntax syntax[] = {
442 [DIR_FFCONCAT ] = { "ffconcat", "kk", 0 },
443 [DIR_FILE ] = { "file", "s", 0 },
444 [DIR_DURATION ] = { "duration", "d", NEEDS_FILE },
445 [DIR_INPOINT ] = { "inpoint", "d", NEEDS_FILE },
446 [DIR_OUTPOINT ] = { "outpoint", "d", NEEDS_FILE },
447 [DIR_FPMETA ] = { "file_packet_meta", "ks", NEEDS_FILE },
448 [DIR_FPMETAS ] = { "file_packet_metadata", "s", NEEDS_FILE },
449 [DIR_OPTION ] = { "option", "ks", NEEDS_FILE | NEEDS_UNSAFE },
450 [DIR_STREAM ] = { "stream", "", 0 },
451 [DIR_EXSID ] = { "exact_stream_id", "i", NEEDS_STREAM },
452 [DIR_STMETA ] = { "stream_meta", "ks", NEEDS_STREAM },
453 [DIR_STCODEC ] = { "stream_codec", "k", NEEDS_STREAM },
454 [DIR_STEDATA ] = { "stream_extradata", "k", NEEDS_STREAM },
455 [DIR_CHAPTER ] = { "chapter", "idd", 0 },
456 };
457
concat_parse_script(AVFormatContext * avf)458 static int concat_parse_script(AVFormatContext *avf)
459 {
460 ConcatContext *cat = avf->priv_data;
461 unsigned nb_files_alloc = 0;
462 AVBPrint bp;
463 uint8_t *cursor, *keyword;
464 ConcatFile *file = NULL;
465 AVStream *stream = NULL;
466 AVChapter *chapter = NULL;
467 unsigned line = 0, arg;
468 const ParseSyntax *dir;
469 char *arg_kw[MAX_ARGS];
470 char *arg_str[MAX_ARGS] = { 0 };
471 int64_t arg_int[MAX_ARGS];
472 int ret;
473
474 av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
475
476 while ((ret = ff_read_line_to_bprint_overwrite(avf->pb, &bp)) >= 0) {
477 line++;
478 cursor = bp.str;
479 keyword = get_keyword(&cursor);
480 if (!*keyword || *keyword == '#')
481 continue;
482 for (dir = syntax; dir < syntax + FF_ARRAY_ELEMS(syntax); dir++)
483 if (!strcmp(dir->keyword, keyword))
484 break;
485 if (dir >= syntax + FF_ARRAY_ELEMS(syntax)) {
486 av_log(avf, AV_LOG_ERROR, "Line %d: unknown keyword '%s'\n",
487 line, keyword);
488 FAIL(AVERROR_INVALIDDATA);
489 }
490
491 /* Flags check */
492 if ((dir->flags & NEEDS_UNSAFE) && cat->safe) {
493 av_log(avf, AV_LOG_ERROR, "Line %d: %s not allowed if safe\n", line, keyword);
494 FAIL(AVERROR_INVALIDDATA);
495 }
496 if ((dir->flags & NEEDS_FILE) && !cat->nb_files) {
497 av_log(avf, AV_LOG_ERROR, "Line %d: %s without file\n", line, keyword);
498 FAIL(AVERROR_INVALIDDATA);
499 }
500 if ((dir->flags & NEEDS_STREAM) && !avf->nb_streams) {
501 av_log(avf, AV_LOG_ERROR, "Line %d: %s without stream\n", line, keyword);
502 FAIL(AVERROR_INVALIDDATA);
503 }
504
505 /* Arguments parsing */
506 for (arg = 0; arg < FF_ARRAY_ELEMS(dir->args) && dir->args[arg]; arg++) {
507 switch (dir->args[arg]) {
508 case 'd': /* duration */
509 arg_kw[arg] = get_keyword(&cursor);
510 ret = av_parse_time(&arg_int[arg], arg_kw[arg], 1);
511 if (ret < 0) {
512 av_log(avf, AV_LOG_ERROR, "Line %d: invalid duration '%s'\n",
513 line, arg_kw[arg]);
514 goto fail;
515 }
516 break;
517 case 'i': /* integer */
518 arg_int[arg] = strtol(get_keyword(&cursor), NULL, 0);
519 break;
520 case 'k': /* keyword */
521 arg_kw[arg] = get_keyword(&cursor);
522 break;
523 case 's': /* string */
524 av_assert0(!arg_str[arg]);
525 arg_str[arg] = av_get_token((const char **)&cursor, SPACE_CHARS);
526 if (!arg_str[arg])
527 FAIL(AVERROR(ENOMEM));
528 if (!*arg_str[arg]) {
529 av_log(avf, AV_LOG_ERROR, "Line %d: string required\n", line);
530 FAIL(AVERROR_INVALIDDATA);
531 }
532 break;
533 default:
534 FAIL(AVERROR_BUG);
535 }
536 }
537
538 /* Directive action */
539 switch ((ParseDirective)(dir - syntax)) {
540
541 case DIR_FFCONCAT:
542 if (strcmp(arg_kw[0], "version") || strcmp(arg_kw[1], "1.0")) {
543 av_log(avf, AV_LOG_ERROR, "Line %d: invalid version\n", line);
544 FAIL(AVERROR_INVALIDDATA);
545 }
546 break;
547
548 case DIR_FILE:
549 ret = add_file(avf, arg_str[0], &file, &nb_files_alloc);
550 arg_str[0] = NULL;
551 if (ret < 0)
552 goto fail;
553 break;
554
555 case DIR_DURATION:
556 file->user_duration = arg_int[0];
557 break;
558
559 case DIR_INPOINT:
560 file->inpoint = arg_int[0];
561 break;
562
563 case DIR_OUTPOINT:
564 file->outpoint = arg_int[0];
565 break;
566
567 case DIR_FPMETA:
568 ret = av_dict_set(&file->metadata, arg_kw[0], arg_str[1], AV_DICT_DONT_STRDUP_VAL);
569 arg_str[1] = NULL;
570 if (ret < 0)
571 FAIL(ret);
572 break;
573
574 case DIR_FPMETAS:
575 if ((ret = av_dict_parse_string(&file->metadata, arg_str[0], "=", "", 0)) < 0) {
576 av_log(avf, AV_LOG_ERROR, "Line %d: failed to parse metadata string\n", line);
577 FAIL(AVERROR_INVALIDDATA);
578 }
579 av_log(avf, AV_LOG_WARNING,
580 "'file_packet_metadata key=value:key=value' is deprecated, "
581 "use multiple 'file_packet_meta key value' instead\n");
582 av_freep(&arg_str[0]);
583 break;
584
585 case DIR_OPTION:
586 ret = av_dict_set(&file->options, arg_kw[0], arg_str[1], AV_DICT_DONT_STRDUP_VAL);
587 arg_str[1] = NULL;
588 if (ret < 0)
589 FAIL(ret);
590 break;
591
592 case DIR_STREAM:
593 stream = avformat_new_stream(avf, NULL);
594 if (!stream)
595 FAIL(AVERROR(ENOMEM));
596 break;
597
598 case DIR_EXSID:
599 stream->id = arg_int[0];
600 break;
601 case DIR_STMETA:
602 ret = av_dict_set(&stream->metadata, arg_kw[0], arg_str[1], AV_DICT_DONT_STRDUP_VAL);
603 arg_str[1] = NULL;
604 if (ret < 0)
605 FAIL(ret);
606 break;
607
608 case DIR_STCODEC: {
609 const AVCodecDescriptor *codec = avcodec_descriptor_get_by_name(arg_kw[0]);
610 if (!codec) {
611 av_log(avf, AV_LOG_ERROR, "Line %d: codec '%s' not found\n", line, arg_kw[0]);
612 FAIL(AVERROR_DECODER_NOT_FOUND);
613 }
614 stream->codecpar->codec_type = codec->type;
615 stream->codecpar->codec_id = codec->id;
616 break;
617 }
618
619 case DIR_STEDATA: {
620 int size = ff_hex_to_data(NULL, arg_kw[0]);
621 ret = ff_alloc_extradata(stream->codecpar, size);
622 if (ret < 0)
623 FAIL(ret);
624 ff_hex_to_data(stream->codecpar->extradata, arg_kw[0]);
625 break;
626 }
627
628 case DIR_CHAPTER:
629 chapter = avpriv_new_chapter(avf, arg_int[0], AV_TIME_BASE_Q,
630 arg_int[1], arg_int[2], NULL);
631 if (!chapter)
632 FAIL(ENOMEM);
633 break;
634
635 default:
636 FAIL(AVERROR_BUG);
637 }
638 }
639
640 fail:
641 for (arg = 0; arg < MAX_ARGS; arg++)
642 av_freep(&arg_str[arg]);
643 av_bprint_finalize(&bp, NULL);
644 return ret == AVERROR_EOF ? 0 : ret;
645 }
646
concat_read_header(AVFormatContext * avf)647 static int concat_read_header(AVFormatContext *avf)
648 {
649 ConcatContext *cat = avf->priv_data;
650 int64_t time = 0;
651 unsigned i;
652 int ret;
653
654 ret = concat_parse_script(avf);
655 if (ret < 0)
656 return ret;
657 if (!cat->nb_files) {
658 av_log(avf, AV_LOG_ERROR, "No files to concat\n");
659 return AVERROR_INVALIDDATA;
660 }
661
662 for (i = 0; i < cat->nb_files; i++) {
663 if (cat->files[i].start_time == AV_NOPTS_VALUE)
664 cat->files[i].start_time = time;
665 else
666 time = cat->files[i].start_time;
667 if (cat->files[i].user_duration == AV_NOPTS_VALUE) {
668 if (cat->files[i].inpoint == AV_NOPTS_VALUE || cat->files[i].outpoint == AV_NOPTS_VALUE ||
669 cat->files[i].outpoint - (uint64_t)cat->files[i].inpoint != av_sat_sub64(cat->files[i].outpoint, cat->files[i].inpoint)
670 )
671 break;
672 cat->files[i].user_duration = cat->files[i].outpoint - cat->files[i].inpoint;
673 }
674 cat->files[i].duration = cat->files[i].user_duration;
675 time += cat->files[i].user_duration;
676 }
677 if (i == cat->nb_files) {
678 avf->duration = time;
679 cat->seekable = 1;
680 }
681
682 cat->stream_match_mode = avf->nb_streams ? MATCH_EXACT_ID :
683 MATCH_ONE_TO_ONE;
684 if ((ret = open_file(avf, 0)) < 0)
685 return ret;
686
687 return 0;
688 }
689
open_next_file(AVFormatContext * avf)690 static int open_next_file(AVFormatContext *avf)
691 {
692 ConcatContext *cat = avf->priv_data;
693 unsigned fileno = cat->cur_file - cat->files;
694
695 cat->cur_file->duration = get_best_effort_duration(cat->cur_file, cat->avf);
696
697 if (++fileno >= cat->nb_files) {
698 cat->eof = 1;
699 return AVERROR_EOF;
700 }
701 return open_file(avf, fileno);
702 }
703
filter_packet(AVFormatContext * avf,ConcatStream * cs,AVPacket * pkt)704 static int filter_packet(AVFormatContext *avf, ConcatStream *cs, AVPacket *pkt)
705 {
706 int ret;
707
708 if (cs->bsf) {
709 ret = av_bsf_send_packet(cs->bsf, pkt);
710 if (ret < 0) {
711 av_log(avf, AV_LOG_ERROR, "h264_mp4toannexb filter "
712 "failed to send input packet\n");
713 return ret;
714 }
715
716 while (!ret)
717 ret = av_bsf_receive_packet(cs->bsf, pkt);
718
719 if (ret < 0 && (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)) {
720 av_log(avf, AV_LOG_ERROR, "h264_mp4toannexb filter "
721 "failed to receive output packet\n");
722 return ret;
723 }
724 }
725 return 0;
726 }
727
728 /* Returns true if the packet dts is greater or equal to the specified outpoint. */
packet_after_outpoint(ConcatContext * cat,AVPacket * pkt)729 static int packet_after_outpoint(ConcatContext *cat, AVPacket *pkt)
730 {
731 if (cat->cur_file->outpoint != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE) {
732 return av_compare_ts(pkt->dts, cat->avf->streams[pkt->stream_index]->time_base,
733 cat->cur_file->outpoint, AV_TIME_BASE_Q) >= 0;
734 }
735 return 0;
736 }
737
concat_read_packet(AVFormatContext * avf,AVPacket * pkt)738 static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
739 {
740 ConcatContext *cat = avf->priv_data;
741 int ret;
742 int64_t delta;
743 ConcatStream *cs;
744 AVStream *st;
745 FFStream *sti;
746
747 if (cat->eof)
748 return AVERROR_EOF;
749
750 if (!cat->avf)
751 return AVERROR(EIO);
752
753 while (1) {
754 ret = av_read_frame(cat->avf, pkt);
755 if (ret == AVERROR_EOF) {
756 if ((ret = open_next_file(avf)) < 0)
757 return ret;
758 continue;
759 }
760 if (ret < 0)
761 return ret;
762 if ((ret = match_streams(avf)) < 0) {
763 return ret;
764 }
765 if (packet_after_outpoint(cat, pkt)) {
766 av_packet_unref(pkt);
767 if ((ret = open_next_file(avf)) < 0)
768 return ret;
769 continue;
770 }
771 cs = &cat->cur_file->streams[pkt->stream_index];
772 if (cs->out_stream_index < 0) {
773 av_packet_unref(pkt);
774 continue;
775 }
776 break;
777 }
778 if ((ret = filter_packet(avf, cs, pkt)) < 0)
779 return ret;
780
781 st = cat->avf->streams[pkt->stream_index];
782 sti = ffstream(st);
783 av_log(avf, AV_LOG_DEBUG, "file:%d stream:%d pts:%s pts_time:%s dts:%s dts_time:%s",
784 (unsigned)(cat->cur_file - cat->files), pkt->stream_index,
785 av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
786 av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
787
788 delta = av_rescale_q(cat->cur_file->start_time - cat->cur_file->file_inpoint,
789 AV_TIME_BASE_Q,
790 cat->avf->streams[pkt->stream_index]->time_base);
791 if (pkt->pts != AV_NOPTS_VALUE)
792 pkt->pts += delta;
793 if (pkt->dts != AV_NOPTS_VALUE)
794 pkt->dts += delta;
795 av_log(avf, AV_LOG_DEBUG, " -> pts:%s pts_time:%s dts:%s dts_time:%s\n",
796 av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
797 av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
798 if (cat->cur_file->metadata) {
799 size_t metadata_len;
800 char* packed_metadata = av_packet_pack_dictionary(cat->cur_file->metadata, &metadata_len);
801 if (!packed_metadata)
802 return AVERROR(ENOMEM);
803 ret = av_packet_add_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA,
804 packed_metadata, metadata_len);
805 if (ret < 0) {
806 av_freep(&packed_metadata);
807 return ret;
808 }
809 }
810
811 if (cat->cur_file->duration == AV_NOPTS_VALUE && sti->cur_dts != AV_NOPTS_VALUE) {
812 int64_t next_dts = av_rescale_q(sti->cur_dts, st->time_base, AV_TIME_BASE_Q);
813 if (cat->cur_file->next_dts == AV_NOPTS_VALUE || next_dts > cat->cur_file->next_dts) {
814 cat->cur_file->next_dts = next_dts;
815 }
816 }
817
818 pkt->stream_index = cs->out_stream_index;
819 return 0;
820 }
821
try_seek(AVFormatContext * avf,int stream,int64_t min_ts,int64_t ts,int64_t max_ts,int flags)822 static int try_seek(AVFormatContext *avf, int stream,
823 int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
824 {
825 ConcatContext *cat = avf->priv_data;
826 int64_t t0 = cat->cur_file->start_time - cat->cur_file->file_inpoint;
827
828 ts -= t0;
829 min_ts = min_ts == INT64_MIN ? INT64_MIN : min_ts - t0;
830 max_ts = max_ts == INT64_MAX ? INT64_MAX : max_ts - t0;
831 if (stream >= 0) {
832 if (stream >= cat->avf->nb_streams)
833 return AVERROR(EIO);
834 ff_rescale_interval(AV_TIME_BASE_Q, cat->avf->streams[stream]->time_base,
835 &min_ts, &ts, &max_ts);
836 }
837 return avformat_seek_file(cat->avf, stream, min_ts, ts, max_ts, flags);
838 }
839
real_seek(AVFormatContext * avf,int stream,int64_t min_ts,int64_t ts,int64_t max_ts,int flags,AVFormatContext * cur_avf)840 static int real_seek(AVFormatContext *avf, int stream,
841 int64_t min_ts, int64_t ts, int64_t max_ts, int flags, AVFormatContext *cur_avf)
842 {
843 ConcatContext *cat = avf->priv_data;
844 int ret, left, right;
845
846 if (stream >= 0) {
847 if (stream >= avf->nb_streams)
848 return AVERROR(EINVAL);
849 ff_rescale_interval(avf->streams[stream]->time_base, AV_TIME_BASE_Q,
850 &min_ts, &ts, &max_ts);
851 }
852
853 left = 0;
854 right = cat->nb_files;
855
856 /* Always support seek to start */
857 if (ts <= 0)
858 right = 1;
859 else if (!cat->seekable)
860 return AVERROR(ESPIPE); /* XXX: can we use it? */
861
862 while (right - left > 1) {
863 int mid = (left + right) / 2;
864 if (ts < cat->files[mid].start_time)
865 right = mid;
866 else
867 left = mid;
868 }
869
870 if (cat->cur_file != &cat->files[left]) {
871 if ((ret = open_file(avf, left)) < 0)
872 return ret;
873 } else {
874 cat->avf = cur_avf;
875 }
876
877 ret = try_seek(avf, stream, min_ts, ts, max_ts, flags);
878 if (ret < 0 &&
879 left < cat->nb_files - 1 &&
880 cat->files[left + 1].start_time < max_ts) {
881 if (cat->cur_file == &cat->files[left])
882 cat->avf = NULL;
883 if ((ret = open_file(avf, left + 1)) < 0)
884 return ret;
885 ret = try_seek(avf, stream, min_ts, ts, max_ts, flags);
886 }
887 return ret;
888 }
889
concat_seek(AVFormatContext * avf,int stream,int64_t min_ts,int64_t ts,int64_t max_ts,int flags)890 static int concat_seek(AVFormatContext *avf, int stream,
891 int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
892 {
893 ConcatContext *cat = avf->priv_data;
894 ConcatFile *cur_file_saved = cat->cur_file;
895 AVFormatContext *cur_avf_saved = cat->avf;
896 int ret;
897
898 if (flags & (AVSEEK_FLAG_BYTE | AVSEEK_FLAG_FRAME))
899 return AVERROR(ENOSYS);
900 cat->avf = NULL;
901 if ((ret = real_seek(avf, stream, min_ts, ts, max_ts, flags, cur_avf_saved)) < 0) {
902 if (cat->cur_file != cur_file_saved) {
903 if (cat->avf)
904 avformat_close_input(&cat->avf);
905 }
906 cat->avf = cur_avf_saved;
907 cat->cur_file = cur_file_saved;
908 } else {
909 if (cat->cur_file != cur_file_saved) {
910 avformat_close_input(&cur_avf_saved);
911 }
912 cat->eof = 0;
913 }
914 return ret;
915 }
916
917 #define OFFSET(x) offsetof(ConcatContext, x)
918 #define DEC AV_OPT_FLAG_DECODING_PARAM
919
920 static const AVOption options[] = {
921 { "safe", "enable safe mode",
922 OFFSET(safe), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, DEC },
923 { "auto_convert", "automatically convert bitstream format",
924 OFFSET(auto_convert), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, DEC },
925 { "segment_time_metadata", "output file segment start time and duration as packet metadata",
926 OFFSET(segment_time_metadata), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC },
927 { NULL }
928 };
929
930 static const AVClass concat_class = {
931 .class_name = "concat demuxer",
932 .item_name = av_default_item_name,
933 .option = options,
934 .version = LIBAVUTIL_VERSION_INT,
935 };
936
937
938 const AVInputFormat ff_concat_demuxer = {
939 .name = "concat",
940 .long_name = NULL_IF_CONFIG_SMALL("Virtual concatenation script"),
941 .priv_data_size = sizeof(ConcatContext),
942 .flags_internal = FF_FMT_INIT_CLEANUP,
943 .read_probe = concat_probe,
944 .read_header = concat_read_header,
945 .read_packet = concat_read_packet,
946 .read_close = concat_read_close,
947 .read_seek2 = concat_seek,
948 .priv_class = &concat_class,
949 };
950