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/avassert.h" 22#include "libavutil/avstring.h" 23#include "libavutil/intreadwrite.h" 24#include "libavutil/opt.h" 25#include "libavutil/parseutils.h" 26#include "avformat.h" 27#include "internal.h" 28#include "url.h" 29 30typedef enum ConcatMatchMode { 31 MATCH_ONE_TO_ONE, 32 MATCH_EXACT_ID, 33} ConcatMatchMode; 34 35typedef struct ConcatStream { 36 AVBitStreamFilterContext *bsf; 37 int out_stream_index; 38} ConcatStream; 39 40typedef struct { 41 char *url; 42 int64_t start_time; 43 int64_t duration; 44 ConcatStream *streams; 45 int nb_streams; 46} ConcatFile; 47 48typedef struct { 49 AVClass *class; 50 ConcatFile *files; 51 ConcatFile *cur_file; 52 unsigned nb_files; 53 AVFormatContext *avf; 54 int safe; 55 int seekable; 56 ConcatMatchMode stream_match_mode; 57 unsigned auto_convert; 58} ConcatContext; 59 60static int concat_probe(AVProbeData *probe) 61{ 62 return memcmp(probe->buf, "ffconcat version 1.0", 20) ? 63 0 : AVPROBE_SCORE_MAX; 64} 65 66static char *get_keyword(uint8_t **cursor) 67{ 68 char *ret = *cursor += strspn(*cursor, SPACE_CHARS); 69 *cursor += strcspn(*cursor, SPACE_CHARS); 70 if (**cursor) { 71 *((*cursor)++) = 0; 72 *cursor += strspn(*cursor, SPACE_CHARS); 73 } 74 return ret; 75} 76 77static int safe_filename(const char *f) 78{ 79 const char *start = f; 80 81 for (; *f; f++) { 82 /* A-Za-z0-9_- */ 83 if (!((unsigned)((*f | 32) - 'a') < 26 || 84 (unsigned)(*f - '0') < 10 || *f == '_' || *f == '-')) { 85 if (f == start) 86 return 0; 87 else if (*f == '/') 88 start = f + 1; 89 else if (*f != '.') 90 return 0; 91 } 92 } 93 return 1; 94} 95 96#define FAIL(retcode) do { ret = (retcode); goto fail; } while(0) 97 98static int add_file(AVFormatContext *avf, char *filename, ConcatFile **rfile, 99 unsigned *nb_files_alloc) 100{ 101 ConcatContext *cat = avf->priv_data; 102 ConcatFile *file; 103 char *url = NULL; 104 const char *proto; 105 size_t url_len, proto_len; 106 int ret; 107 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)); 111 } 112 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] == ',')) { 117 url = filename; 118 filename = NULL; 119 } else { 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); 124 av_freep(&filename); 125 } 126 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; 134 *nb_files_alloc = n; 135 } 136 137 file = &cat->files[cat->nb_files++]; 138 memset(file, 0, sizeof(*file)); 139 *rfile = file; 140 141 file->url = url; 142 file->start_time = AV_NOPTS_VALUE; 143 file->duration = AV_NOPTS_VALUE; 144 145 return 0; 146 147fail: 148 av_free(url); 149 av_free(filename); 150 return ret; 151} 152 153static int copy_stream_props(AVStream *st, AVStream *source_st) 154{ 155 int ret; 156 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); 161 if (ret < 0) 162 return ret; 163 } 164 memcpy(st->codec->extradata, source_st->codec->extradata, 165 source_st->codec->extradata_size); 166 return 0; 167 } 168 if ((ret = avcodec_copy_context(st->codec, source_st->codec)) < 0) 169 return ret; 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; 174 return 0; 175} 176 177static int detect_stream_specific(AVFormatContext *avf, int idx) 178{ 179 ConcatContext *cat = avf->priv_data; 180 AVStream *st = cat->avf->streams[idx]; 181 ConcatStream *cs = &cat->cur_file->streams[idx]; 182 AVBitStreamFilterContext *bsf; 183 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; 192 } 193 cs->bsf = bsf; 194 } 195 return 0; 196} 197 198static int match_streams_one_to_one(AVFormatContext *avf) 199{ 200 ConcatContext *cat = avf->priv_data; 201 AVStream *st; 202 int i, ret; 203 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]; 207 } else { 208 if (!(st = avformat_new_stream(avf, NULL))) 209 return AVERROR(ENOMEM); 210 } 211 if ((ret = copy_stream_props(st, cat->avf->streams[i])) < 0) 212 return ret; 213 cat->cur_file->streams[i].out_stream_index = i; 214 } 215 return 0; 216} 217 218static int match_streams_exact_id(AVFormatContext *avf) 219{ 220 ConcatContext *cat = avf->priv_data; 221 AVStream *st; 222 int i, j, ret; 223 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", 230 i, j, st->id); 231 if ((ret = copy_stream_props(avf->streams[j], st)) < 0) 232 return ret; 233 cat->cur_file->streams[i].out_stream_index = j; 234 } 235 } 236 } 237 return 0; 238} 239 240static int match_streams(AVFormatContext *avf) 241{ 242 ConcatContext *cat = avf->priv_data; 243 ConcatStream *map; 244 int i, ret; 245 246 if (cat->cur_file->nb_streams >= cat->avf->nb_streams) 247 return 0; 248 map = av_realloc(cat->cur_file->streams, 249 cat->avf->nb_streams * sizeof(*map)); 250 if (!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)); 255 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); 261 break; 262 case MATCH_EXACT_ID: 263 ret = match_streams_exact_id(avf); 264 break; 265 default: 266 ret = AVERROR_BUG; 267 } 268 if (ret < 0) 269 return ret; 270 for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) 271 if ((ret = detect_stream_specific(avf, i)) < 0) 272 return ret; 273 cat->cur_file->nb_streams = cat->avf->nb_streams; 274 return 0; 275} 276 277static int open_file(AVFormatContext *avf, unsigned fileno) 278{ 279 ConcatContext *cat = avf->priv_data; 280 ConcatFile *file = &cat->files[fileno]; 281 int ret; 282 283 if (cat->avf) 284 avformat_close_input(&cat->avf); 285 286 cat->avf = avformat_alloc_context(); 287 if (!cat->avf) 288 return AVERROR(ENOMEM); 289 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); 295 return ret; 296 } 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) 303 return ret; 304 return 0; 305} 306 307static int concat_read_close(AVFormatContext *avf) 308{ 309 ConcatContext *cat = avf->priv_data; 310 unsigned i; 311 312 if (cat->avf) 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); 317 } 318 av_freep(&cat->files); 319 return 0; 320} 321 322static int concat_read_header(AVFormatContext *avf) 323{ 324 ConcatContext *cat = avf->priv_data; 325 uint8_t buf[4096]; 326 uint8_t *cursor, *keyword; 327 int ret, line = 0, i; 328 unsigned nb_files_alloc = 0; 329 ConcatFile *file = NULL; 330 int64_t time = 0; 331 332 while (1) { 333 if ((ret = ff_get_line(avf->pb, buf, sizeof(buf))) <= 0) 334 break; 335 line++; 336 cursor = buf; 337 keyword = get_keyword(&cursor); 338 if (!*keyword || *keyword == '#') 339 continue; 340 341 if (!strcmp(keyword, "file")) { 342 char *filename = av_get_token((const char **)&cursor, SPACE_CHARS); 343 if (!filename) { 344 av_log(avf, AV_LOG_ERROR, "Line %d: filename required\n", line); 345 FAIL(AVERROR_INVALIDDATA); 346 } 347 if ((ret = add_file(avf, filename, &file, &nb_files_alloc)) < 0) 348 FAIL(ret); 349 } else if (!strcmp(keyword, "duration")) { 350 char *dur_str = get_keyword(&cursor); 351 int64_t dur; 352 if (!file) { 353 av_log(avf, AV_LOG_ERROR, "Line %d: duration without file\n", 354 line); 355 FAIL(AVERROR_INVALIDDATA); 356 } 357 if ((ret = av_parse_time(&dur, dur_str, 1)) < 0) { 358 av_log(avf, AV_LOG_ERROR, "Line %d: invalid duration '%s'\n", 359 line, dur_str); 360 FAIL(ret); 361 } 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", 369 line); 370 FAIL(AVERROR_INVALIDDATA); 371 } 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); 380 } 381 if (cat->safe < 0) 382 cat->safe = 1; 383 } else { 384 av_log(avf, AV_LOG_ERROR, "Line %d: unknown keyword '%s'\n", 385 line, keyword); 386 FAIL(AVERROR_INVALIDDATA); 387 } 388 } 389 if (ret < 0) 390 FAIL(ret); 391 if (!cat->nb_files) 392 FAIL(AVERROR_INVALIDDATA); 393 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; 397 else 398 time = cat->files[i].start_time; 399 if (cat->files[i].duration == AV_NOPTS_VALUE) 400 break; 401 time += cat->files[i].duration; 402 } 403 if (i == cat->nb_files) { 404 avf->duration = time; 405 cat->seekable = 1; 406 } 407 408 cat->stream_match_mode = avf->nb_streams ? MATCH_EXACT_ID : 409 MATCH_ONE_TO_ONE; 410 if ((ret = open_file(avf, 0)) < 0) 411 FAIL(ret); 412 return 0; 413 414fail: 415 concat_read_close(avf); 416 return ret; 417} 418 419static int open_next_file(AVFormatContext *avf) 420{ 421 ConcatContext *cat = avf->priv_data; 422 unsigned fileno = cat->cur_file - cat->files; 423 424 if (cat->cur_file->duration == AV_NOPTS_VALUE) 425 cat->cur_file->duration = cat->avf->duration; 426 427 if (++fileno >= cat->nb_files) 428 return AVERROR_EOF; 429 return open_file(avf, fileno); 430} 431 432static int filter_packet(AVFormatContext *avf, ConcatStream *cs, AVPacket *pkt) 433{ 434 AVStream *st = avf->streams[cs->out_stream_index]; 435 AVBitStreamFilterContext *bsf; 436 AVPacket pkt2; 437 int ret; 438 439 av_assert0(cs->out_stream_index >= 0); 440 for (bsf = cs->bsf; bsf; bsf = bsf->next) { 441 pkt2 = *pkt; 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)); 446 if (ret < 0) { 447 av_packet_unref(pkt); 448 return ret; 449 } 450 av_assert0(pkt2.buf); 451 if (ret == 0 && pkt2.data != pkt->data) { 452 if ((ret = av_copy_packet(&pkt2, pkt)) < 0) { 453 av_free(pkt2.data); 454 return ret; 455 } 456 ret = 1; 457 } 458 if (ret > 0) { 459 av_free_packet(pkt); 460 pkt2.buf = av_buffer_create(pkt2.data, pkt2.size, 461 av_buffer_default_free, NULL, 0); 462 if (!pkt2.buf) { 463 av_free(pkt2.data); 464 return AVERROR(ENOMEM); 465 } 466 } 467 *pkt = pkt2; 468 } 469 return 0; 470} 471 472static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) 473{ 474 ConcatContext *cat = avf->priv_data; 475 int ret; 476 int64_t delta; 477 ConcatStream *cs; 478 479 while (1) { 480 ret = av_read_frame(cat->avf, pkt); 481 if (ret == AVERROR_EOF) { 482 if ((ret = open_next_file(avf)) < 0) 483 return ret; 484 continue; 485 } 486 if (ret < 0) 487 return ret; 488 if ((ret = match_streams(avf)) < 0) { 489 av_packet_unref(pkt); 490 return ret; 491 } 492 cs = &cat->cur_file->streams[pkt->stream_index]; 493 if (cs->out_stream_index < 0) { 494 av_packet_unref(pkt); 495 continue; 496 } 497 pkt->stream_index = cs->out_stream_index; 498 break; 499 } 500 if ((ret = filter_packet(avf, cs, pkt))) 501 return ret; 502 503 delta = av_rescale_q(cat->cur_file->start_time - cat->avf->start_time, 504 AV_TIME_BASE_Q, 505 cat->avf->streams[pkt->stream_index]->time_base); 506 if (pkt->pts != AV_NOPTS_VALUE) 507 pkt->pts += delta; 508 if (pkt->dts != AV_NOPTS_VALUE) 509 pkt->dts += delta; 510 return ret; 511} 512 513static void rescale_interval(AVRational tb_in, AVRational tb_out, 514 int64_t *min_ts, int64_t *ts, int64_t *max_ts) 515{ 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); 521} 522 523static int try_seek(AVFormatContext *avf, int stream, 524 int64_t min_ts, int64_t ts, int64_t max_ts, int flags) 525{ 526 ConcatContext *cat = avf->priv_data; 527 int64_t t0 = cat->cur_file->start_time - cat->avf->start_time; 528 529 ts -= t0; 530 min_ts = min_ts == INT64_MIN ? INT64_MIN : min_ts - t0; 531 max_ts = max_ts == INT64_MAX ? INT64_MAX : max_ts - t0; 532 if (stream >= 0) { 533 if (stream >= cat->avf->nb_streams) 534 return AVERROR(EIO); 535 rescale_interval(AV_TIME_BASE_Q, cat->avf->streams[stream]->time_base, 536 &min_ts, &ts, &max_ts); 537 } 538 return avformat_seek_file(cat->avf, stream, min_ts, ts, max_ts, flags); 539} 540 541static int real_seek(AVFormatContext *avf, int stream, 542 int64_t min_ts, int64_t ts, int64_t max_ts, int flags) 543{ 544 ConcatContext *cat = avf->priv_data; 545 int ret, left, right; 546 547 if (stream >= 0) { 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); 552 } 553 554 left = 0; 555 right = cat->nb_files; 556 while (right - left > 1) { 557 int mid = (left + right) / 2; 558 if (ts < cat->files[mid].start_time) 559 right = mid; 560 else 561 left = mid; 562 } 563 564 if ((ret = open_file(avf, left)) < 0) 565 return ret; 566 567 ret = try_seek(avf, stream, min_ts, ts, max_ts, flags); 568 if (ret < 0 && 569 left < cat->nb_files - 1 && 570 cat->files[left + 1].start_time < max_ts) { 571 if ((ret = open_file(avf, left + 1)) < 0) 572 return ret; 573 ret = try_seek(avf, stream, min_ts, ts, max_ts, flags); 574 } 575 return ret; 576} 577 578static int concat_seek(AVFormatContext *avf, int stream, 579 int64_t min_ts, int64_t ts, int64_t max_ts, int flags) 580{ 581 ConcatContext *cat = avf->priv_data; 582 ConcatFile *cur_file_saved = cat->cur_file; 583 AVFormatContext *cur_avf_saved = cat->avf; 584 int ret; 585 586 if (!cat->seekable) 587 return AVERROR(ESPIPE); /* XXX: can we use it? */ 588 if (flags & (AVSEEK_FLAG_BYTE | AVSEEK_FLAG_FRAME)) 589 return AVERROR(ENOSYS); 590 cat->avf = NULL; 591 if ((ret = real_seek(avf, stream, min_ts, ts, max_ts, flags)) < 0) { 592 if (cat->avf) 593 avformat_close_input(&cat->avf); 594 cat->avf = cur_avf_saved; 595 cat->cur_file = cur_file_saved; 596 } else { 597 avformat_close_input(&cur_avf_saved); 598 } 599 return ret; 600} 601 602#define OFFSET(x) offsetof(ConcatContext, x) 603#define DEC AV_OPT_FLAG_DECODING_PARAM 604 605static 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 }, 610 { NULL } 611}; 612 613static const AVClass concat_class = { 614 .class_name = "concat demuxer", 615 .item_name = av_default_item_name, 616 .option = options, 617 .version = LIBAVUTIL_VERSION_INT, 618}; 619 620 621AVInputFormat ff_concat_demuxer = { 622 .name = "concat", 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, 631}; 632