Advertisement
Guest User

Untitled

a guest
Jul 14th, 2015
214
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 20.79 KB | None | 0 0
  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 "libavutil/timestamp.h"
  27. #include "avformat.h"
  28. #include "internal.h"
  29. #include "url.h"
  30.  
  31. typedef enum ConcatMatchMode {
  32.     MATCH_ONE_TO_ONE,
  33.     MATCH_EXACT_ID,
  34. } ConcatMatchMode;
  35.  
  36. typedef struct ConcatStream {
  37.     AVBitStreamFilterContext *bsf;
  38.     int out_stream_index;
  39. } ConcatStream;
  40.  
  41. typedef struct {
  42.     char *url;
  43.     int64_t start_time;
  44.     int64_t duration;
  45.     ConcatStream *streams;
  46.     int nb_streams;
  47. } ConcatFile;
  48.  
  49. typedef struct {
  50.     AVClass *class;
  51.     ConcatFile *files;
  52.     ConcatFile *cur_file;
  53.     unsigned nb_files;
  54.     AVFormatContext *avf;
  55.     int safe;
  56.     int seekable;
  57.     ConcatMatchMode stream_match_mode;
  58.     unsigned auto_convert;
  59. } ConcatContext;
  60.  
  61. static int concat_probe(AVProbeData *probe)
  62. {
  63.     return memcmp(probe->buf, "ffconcat version 1.0", 20) ?
  64.            0 : AVPROBE_SCORE_MAX;
  65. }
  66.  
  67. static char *get_keyword(uint8_t **cursor)
  68. {
  69.     char *ret = *cursor += strspn(*cursor, SPACE_CHARS);
  70.     *cursor += strcspn(*cursor, SPACE_CHARS);
  71.     if (**cursor) {
  72.         *((*cursor)++) = 0;
  73.         *cursor += strspn(*cursor, SPACE_CHARS);
  74.     }
  75.     return ret;
  76. }
  77.  
  78. static int safe_filename(const char *f)
  79. {
  80.     const char *start = f;
  81.  
  82.     for (; *f; f++) {
  83.         /* A-Za-z0-9_- */
  84.         if (!((unsigned)((*f | 32) - 'a') < 26 ||
  85.               (unsigned)(*f - '0') < 10 || *f == '_' || *f == '-')) {
  86.             if (f == start)
  87.                 return 0;
  88.             else if (*f == '/')
  89.                 start = f + 1;
  90.             else if (*f != '.')
  91.                 return 0;
  92.         }
  93.     }
  94.     return 1;
  95. }
  96.  
  97. #define FAIL(retcode) do { ret = (retcode); goto fail; } while(0)
  98.  
  99. static int add_file(AVFormatContext *avf, char *filename, ConcatFile **rfile,
  100.                     unsigned *nb_files_alloc)
  101. {
  102.     ConcatContext *cat = avf->priv_data;
  103.     ConcatFile *file;
  104.     char *url = NULL;
  105.     const char *proto;
  106.     size_t url_len, proto_len;
  107.     int ret;
  108.  
  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));
  112.     }
  113.  
  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] == ',')) {
  118.         url = filename;
  119.         filename = NULL;
  120.     } else {
  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);
  125.         av_freep(&filename);
  126.     }
  127.  
  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;
  135.         *nb_files_alloc = n;
  136.     }
  137.  
  138.     file = &cat->files[cat->nb_files++];
  139.     memset(file, 0, sizeof(*file));
  140.     *rfile = file;
  141.  
  142.     file->url        = url;
  143.     file->start_time = AV_NOPTS_VALUE;
  144.     file->duration   = AV_NOPTS_VALUE;
  145.  
  146.     return 0;
  147.  
  148. fail:
  149.     av_free(url);
  150.     av_free(filename);
  151.     return ret;
  152. }
  153.  
  154. static int copy_stream_props(AVStream *st, AVStream *source_st)
  155. {
  156.     int ret;
  157.  
  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);
  162.             if (ret < 0)
  163.                 return ret;
  164.         }
  165.         memcpy(st->codec->extradata, source_st->codec->extradata,
  166.                source_st->codec->extradata_size);
  167.         return 0;
  168.     }
  169.     if ((ret = avcodec_copy_context(st->codec, source_st->codec)) < 0)
  170.         return ret;
  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;
  175.  
  176.     av_dict_copy(&st->metadata, source_st->metadata, 0);
  177.     return 0;
  178. }
  179.  
  180. static int detect_stream_specific(AVFormatContext *avf, int idx)
  181. {
  182.     ConcatContext *cat = avf->priv_data;
  183.     AVStream *st = cat->avf->streams[idx];
  184.     ConcatStream *cs = &cat->cur_file->streams[idx];
  185.     AVBitStreamFilterContext *bsf;
  186.  
  187.     if (cat->auto_convert && st->codec->codec_id == AV_CODEC_ID_H264 &&
  188.         (st->codec->extradata_size < 4 || AV_RB32(st->codec->extradata) != 1)) {
  189.         av_log(cat->avf, AV_LOG_INFO,
  190.                "Auto-inserting h264_mp4toannexb bitstream filter\n");
  191.         if (!(bsf = av_bitstream_filter_init("h264_mp4toannexb"))) {
  192.             av_log(avf, AV_LOG_ERROR, "h264_mp4toannexb bitstream filter "
  193.                    "required for H.264 streams\n");
  194.             return AVERROR_BSF_NOT_FOUND;
  195.         }
  196.         cs->bsf = bsf;
  197.     }
  198.     return 0;
  199. }
  200.  
  201. static int match_streams_one_to_one(AVFormatContext *avf)
  202. {
  203.     ConcatContext *cat = avf->priv_data;
  204.     AVStream *st;
  205.     int i, ret;
  206.  
  207.     for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) {
  208.         if (i < avf->nb_streams) {
  209.             st = avf->streams[i];
  210.         } else {
  211.             if (!(st = avformat_new_stream(avf, NULL)))
  212.                 return AVERROR(ENOMEM);
  213.         }
  214.         if ((ret = copy_stream_props(st, cat->avf->streams[i])) < 0)
  215.             return ret;
  216.         cat->cur_file->streams[i].out_stream_index = i;
  217.     }
  218.     return 0;
  219. }
  220.  
  221. static int match_streams_exact_id(AVFormatContext *avf)
  222. {
  223.     ConcatContext *cat = avf->priv_data;
  224.     AVStream *st;
  225.     int i, j, ret;
  226.  
  227.     for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) {
  228.         st = cat->avf->streams[i];
  229.         for (j = 0; j < avf->nb_streams; j++) {
  230.             if (avf->streams[j]->id == st->id) {
  231.                 av_log(avf, AV_LOG_VERBOSE,
  232.                        "Match slave stream #%d with stream #%d id 0x%x\n",
  233.                        i, j, st->id);
  234.                 if ((ret = copy_stream_props(avf->streams[j], st)) < 0)
  235.                     return ret;
  236.                 cat->cur_file->streams[i].out_stream_index = j;
  237.             }
  238.         }
  239.     }
  240.     return 0;
  241. }
  242.  
  243. static int match_streams(AVFormatContext *avf)
  244. {
  245.     ConcatContext *cat = avf->priv_data;
  246.     ConcatStream *map;
  247.     int i, ret;
  248.  
  249.     if (cat->cur_file->nb_streams >= cat->avf->nb_streams)
  250.         return 0;
  251.     map = av_realloc(cat->cur_file->streams,
  252.                      cat->avf->nb_streams * sizeof(*map));
  253.     if (!map)
  254.         return AVERROR(ENOMEM);
  255.     cat->cur_file->streams = map;
  256.     memset(map + cat->cur_file->nb_streams, 0,
  257.            (cat->avf->nb_streams - cat->cur_file->nb_streams) * sizeof(*map));
  258.  
  259.     for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++)
  260.         map[i].out_stream_index = -1;
  261.     switch (cat->stream_match_mode) {
  262.     case MATCH_ONE_TO_ONE:
  263.         ret = match_streams_one_to_one(avf);
  264.         break;
  265.     case MATCH_EXACT_ID:
  266.         ret = match_streams_exact_id(avf);
  267.         break;
  268.     default:
  269.         ret = AVERROR_BUG;
  270.     }
  271.     if (ret < 0)
  272.         return ret;
  273.     for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++)
  274.         if ((ret = detect_stream_specific(avf, i)) < 0)
  275.             return ret;
  276.     cat->cur_file->nb_streams = cat->avf->nb_streams;
  277.     return 0;
  278. }
  279.  
  280. static int open_file(AVFormatContext *avf, unsigned fileno)
  281. {
  282.     ConcatContext *cat = avf->priv_data;
  283.     ConcatFile *file = &cat->files[fileno];
  284.     int ret;
  285.  
  286.     if (cat->avf)
  287.         avformat_close_input(&cat->avf);
  288.  
  289.     cat->avf = avformat_alloc_context();
  290.     if (!cat->avf)
  291.         return AVERROR(ENOMEM);
  292.  
  293.     cat->avf->interrupt_callback = avf->interrupt_callback;
  294.  
  295.     if ((ret = ff_copy_whitelists(cat->avf, avf)) < 0)
  296.         return ret;
  297.  
  298.     if ((ret = avformat_open_input(&cat->avf, file->url, NULL, NULL)) < 0 ||
  299.         (ret = avformat_find_stream_info(cat->avf, NULL)) < 0) {
  300.         av_log(avf, AV_LOG_ERROR, "Impossible to open '%s'\n", file->url);
  301.         avformat_close_input(&cat->avf);
  302.         return ret;
  303.     }
  304.     printf("FILE=%s\n",file->url);
  305.     cat->cur_file = file;
  306.     if (file->start_time == AV_NOPTS_VALUE)
  307.         file->start_time = !fileno ? 0 :
  308.                            cat->files[fileno - 1].start_time +
  309.                            cat->files[fileno - 1].duration;
  310.     if ((ret = match_streams(avf)) < 0)
  311.         return ret;
  312.     return 0;
  313. }
  314.  
  315. static int concat_read_close(AVFormatContext *avf)
  316. {
  317.     ConcatContext *cat = avf->priv_data;
  318.     unsigned i;
  319.  
  320.     if (cat->avf)
  321.         avformat_close_input(&cat->avf);
  322.     for (i = 0; i < cat->nb_files; i++) {
  323.         av_freep(&cat->files[i].url);
  324.         av_freep(&cat->files[i].streams);
  325.     }
  326.     av_freep(&cat->files);
  327.     return 0;
  328. }
  329.  
  330. static int concat_read_header(AVFormatContext *avf)
  331. {
  332.     ConcatContext *cat = avf->priv_data;
  333.     uint8_t buf[4096];
  334.     uint8_t *cursor, *keyword;
  335.     int ret, line = 0, i;
  336.     unsigned nb_files_alloc = 0;
  337.     ConcatFile *file = NULL;
  338.     int64_t time = 0;
  339.  
  340.     while (1) {
  341.         if ((ret = ff_get_line(avf->pb, buf, sizeof(buf))) <= 0)
  342.             break;
  343.         line++;
  344.         cursor = buf;
  345.         keyword = get_keyword(&cursor);
  346.         if (!*keyword || *keyword == '#')
  347.             continue;
  348.  
  349.         if (!strcmp(keyword, "file")) {
  350.             char *filename = av_get_token((const char **)&cursor, SPACE_CHARS);
  351.             if (!filename) {
  352.                 av_log(avf, AV_LOG_ERROR, "Line %d: filename required\n", line);
  353.                 FAIL(AVERROR_INVALIDDATA);
  354.             }
  355.             if ((ret = add_file(avf, filename, &file, &nb_files_alloc)) < 0)
  356.                 goto fail;
  357.         } else if (!strcmp(keyword, "duration")) {
  358.             char *dur_str = get_keyword(&cursor);
  359.             int64_t dur;
  360.             if (!file) {
  361.                 av_log(avf, AV_LOG_ERROR, "Line %d: duration without file\n",
  362.                        line);
  363.                 FAIL(AVERROR_INVALIDDATA);
  364.             }
  365.             if ((ret = av_parse_time(&dur, dur_str, 1)) < 0) {
  366.                 av_log(avf, AV_LOG_ERROR, "Line %d: invalid duration '%s'\n",
  367.                        line, dur_str);
  368.                 goto fail;
  369.             }
  370.             file->duration = dur;
  371.         } else if (!strcmp(keyword, "stream")) {
  372.             if (!avformat_new_stream(avf, NULL))
  373.                 FAIL(AVERROR(ENOMEM));
  374.         } else if (!strcmp(keyword, "exact_stream_id")) {
  375.             if (!avf->nb_streams) {
  376.                 av_log(avf, AV_LOG_ERROR, "Line %d: exact_stream_id without stream\n",
  377.                        line);
  378.                 FAIL(AVERROR_INVALIDDATA);
  379.             }
  380.             avf->streams[avf->nb_streams - 1]->id =
  381.                 strtol(get_keyword(&cursor), NULL, 0);
  382.         } else if (!strcmp(keyword, "ffconcat")) {
  383.             char *ver_kw  = get_keyword(&cursor);
  384.             char *ver_val = get_keyword(&cursor);
  385.             if (strcmp(ver_kw, "version") || strcmp(ver_val, "1.0")) {
  386.                 av_log(avf, AV_LOG_ERROR, "Line %d: invalid version\n", line);
  387.                 FAIL(AVERROR_INVALIDDATA);
  388.             }
  389.             if (cat->safe < 0)
  390.                 cat->safe = 1;
  391.         } else {
  392.             av_log(avf, AV_LOG_ERROR, "Line %d: unknown keyword '%s'\n",
  393.                    line, keyword);
  394.             FAIL(AVERROR_INVALIDDATA);
  395.         }
  396.     }
  397.     if (ret < 0)
  398.         goto fail;
  399.     if (!cat->nb_files)
  400.         FAIL(AVERROR_INVALIDDATA);
  401.  
  402.     for (i = 0; i < cat->nb_files; i++) {
  403.         if (cat->files[i].start_time == AV_NOPTS_VALUE)
  404.             cat->files[i].start_time = time;
  405.         else
  406.             time = cat->files[i].start_time;
  407.         if (cat->files[i].duration == AV_NOPTS_VALUE)
  408.             break;
  409.         time += cat->files[i].duration;
  410.     }
  411.     if (i == cat->nb_files) {
  412.         avf->duration = time;
  413.         cat->seekable = 1;
  414.     }
  415.  
  416.     cat->stream_match_mode = avf->nb_streams ? MATCH_EXACT_ID :
  417.                                                MATCH_ONE_TO_ONE;
  418.     if ((ret = open_file(avf, 0)) < 0)
  419.         goto fail;
  420.     return 0;
  421.  
  422. fail:
  423.     concat_read_close(avf);
  424.     return ret;
  425. }
  426.  
  427. static int open_next_file(AVFormatContext *avf)
  428. {
  429.     ConcatContext *cat = avf->priv_data;
  430.     unsigned fileno = cat->cur_file - cat->files;
  431.  
  432.     if (cat->cur_file->duration == AV_NOPTS_VALUE)
  433.         cat->cur_file->duration = cat->avf->duration;
  434.  
  435.     if (++fileno >= cat->nb_files)
  436.         return AVERROR_EOF;
  437.     return open_file(avf, fileno);
  438. }
  439.  
  440. static int filter_packet(AVFormatContext *avf, ConcatStream *cs, AVPacket *pkt)
  441. {
  442.     AVStream *st = avf->streams[cs->out_stream_index];
  443.     AVBitStreamFilterContext *bsf;
  444.     AVPacket pkt2;
  445.     int ret;
  446.  
  447.     av_assert0(cs->out_stream_index >= 0);
  448.     for (bsf = cs->bsf; bsf; bsf = bsf->next) {
  449.         pkt2 = *pkt;
  450.         ret = av_bitstream_filter_filter(bsf, st->codec, NULL,
  451.                                          &pkt2.data, &pkt2.size,
  452.                                          pkt->data, pkt->size,
  453.                                          !!(pkt->flags & AV_PKT_FLAG_KEY));
  454.         if (ret < 0) {
  455.             av_packet_unref(pkt);
  456.             return ret;
  457.         }
  458.         av_assert0(pkt2.buf);
  459.         if (ret == 0 && pkt2.data != pkt->data) {
  460.             if ((ret = av_copy_packet(&pkt2, pkt)) < 0) {
  461.                 av_free(pkt2.data);
  462.                 return ret;
  463.             }
  464.             ret = 1;
  465.         }
  466.         if (ret > 0) {
  467.             av_free_packet(pkt);
  468.             pkt2.buf = av_buffer_create(pkt2.data, pkt2.size,
  469.                                         av_buffer_default_free, NULL, 0);
  470.             if (!pkt2.buf) {
  471.                 av_free(pkt2.data);
  472.                 return AVERROR(ENOMEM);
  473.             }
  474.         }
  475.         *pkt = pkt2;
  476.     }
  477.     return 0;
  478. }
  479.  
  480. static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
  481. {
  482.     ConcatContext *cat = avf->priv_data;
  483.     int ret;
  484.     int64_t file_start_time, delta;
  485.     ConcatStream *cs;
  486.     AVStream *st;
  487.  
  488.     if (!cat->avf)
  489.         return AVERROR(EIO);
  490.  
  491.     while (1) {
  492.         ret = av_read_frame(cat->avf, pkt);
  493.         if (ret == AVERROR_EOF) {
  494.             if ((ret = open_next_file(avf)) < 0)
  495.                 return ret;
  496.             continue;
  497.         }
  498.         if (ret < 0)
  499.             return ret;
  500.         if ((ret = match_streams(avf)) < 0) {
  501.             av_packet_unref(pkt);
  502.             return ret;
  503.         }
  504.         cs = &cat->cur_file->streams[pkt->stream_index];
  505.         if (cs->out_stream_index < 0) {
  506.             av_packet_unref(pkt);
  507.             continue;
  508.         }
  509.         pkt->stream_index = cs->out_stream_index;
  510.         break;
  511.     }
  512.     if ((ret = filter_packet(avf, cs, pkt)))
  513.         return ret;
  514.  
  515.     st = cat->avf->streams[pkt->stream_index];
  516.     av_log(avf, AV_LOG_DEBUG, "file:%d stream:%d pts:%s pts_time:%s dts:%s dts_time:%s",
  517.            (unsigned)(cat->cur_file - cat->files), pkt->stream_index,
  518.            av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
  519.            av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
  520.  
  521.     file_start_time = cat->avf->start_time;
  522.     if (file_start_time == AV_NOPTS_VALUE)
  523.         file_start_time = 0;
  524.     delta = av_rescale_q(cat->cur_file->start_time - file_start_time,
  525.                          AV_TIME_BASE_Q,
  526.                          cat->avf->streams[pkt->stream_index]->time_base);
  527.     if (pkt->pts != AV_NOPTS_VALUE)
  528.         pkt->pts += delta;
  529.     if (pkt->dts != AV_NOPTS_VALUE)
  530.         pkt->dts += delta;
  531.     av_log(avf, AV_LOG_DEBUG, " -> pts:%s pts_time:%s dts:%s dts_time:%s\n",
  532.            av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
  533.            av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
  534.     return ret;
  535. }
  536.  
  537. static void rescale_interval(AVRational tb_in, AVRational tb_out,
  538.                              int64_t *min_ts, int64_t *ts, int64_t *max_ts)
  539. {
  540.     *ts     = av_rescale_q    (*    ts, tb_in, tb_out);
  541.     *min_ts = av_rescale_q_rnd(*min_ts, tb_in, tb_out,
  542.                                AV_ROUND_UP   | AV_ROUND_PASS_MINMAX);
  543.     *max_ts = av_rescale_q_rnd(*max_ts, tb_in, tb_out,
  544.                                AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
  545. }
  546.  
  547. static int try_seek(AVFormatContext *avf, int stream,
  548.                     int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
  549. {
  550.     ConcatContext *cat = avf->priv_data;
  551.     int64_t t0 = cat->cur_file->start_time - cat->avf->start_time;
  552.  
  553.     ts -= t0;
  554.     min_ts = min_ts == INT64_MIN ? INT64_MIN : min_ts - t0;
  555.     max_ts = max_ts == INT64_MAX ? INT64_MAX : max_ts - t0;
  556.     if (stream >= 0) {
  557.         if (stream >= cat->avf->nb_streams)
  558.             return AVERROR(EIO);
  559.         rescale_interval(AV_TIME_BASE_Q, cat->avf->streams[stream]->time_base,
  560.                          &min_ts, &ts, &max_ts);
  561.     }
  562.     return avformat_seek_file(cat->avf, stream, min_ts, ts, max_ts, flags);
  563. }
  564.  
  565. static int real_seek(AVFormatContext *avf, int stream,
  566.                      int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
  567. {
  568.     ConcatContext *cat = avf->priv_data;
  569.     int ret, left, right;
  570.  
  571.     if (stream >= 0) {
  572.         if (stream >= avf->nb_streams)
  573.             return AVERROR(EINVAL);
  574.         rescale_interval(avf->streams[stream]->time_base, AV_TIME_BASE_Q,
  575.                          &min_ts, &ts, &max_ts);
  576.     }
  577.  
  578.     left  = 0;
  579.     right = cat->nb_files;
  580.     while (right - left > 1) {
  581.         int mid = (left + right) / 2;
  582.         if (ts < cat->files[mid].start_time)
  583.             right = mid;
  584.         else
  585.             left  = mid;
  586.     }
  587.  
  588.     if ((ret = open_file(avf, left)) < 0)
  589.         return ret;
  590.  
  591.     ret = try_seek(avf, stream, min_ts, ts, max_ts, flags);
  592.     if (ret < 0 &&
  593.         left < cat->nb_files - 1 &&
  594.         cat->files[left + 1].start_time < max_ts) {
  595.         if ((ret = open_file(avf, left + 1)) < 0)
  596.             return ret;
  597.         ret = try_seek(avf, stream, min_ts, ts, max_ts, flags);
  598.     }
  599.     return ret;
  600. }
  601.  
  602. static int concat_seek(AVFormatContext *avf, int stream,
  603.                        int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
  604. {
  605.     ConcatContext *cat = avf->priv_data;
  606.     ConcatFile *cur_file_saved = cat->cur_file;
  607.     AVFormatContext *cur_avf_saved = cat->avf;
  608.     int ret;
  609.  
  610.     if (!cat->seekable)
  611.         return AVERROR(ESPIPE); /* XXX: can we use it? */
  612.     if (flags & (AVSEEK_FLAG_BYTE | AVSEEK_FLAG_FRAME))
  613.         return AVERROR(ENOSYS);
  614.     cat->avf = NULL;
  615.     if ((ret = real_seek(avf, stream, min_ts, ts, max_ts, flags)) < 0) {
  616.         if (cat->avf)
  617.             avformat_close_input(&cat->avf);
  618.         cat->avf      = cur_avf_saved;
  619.         cat->cur_file = cur_file_saved;
  620.     } else {
  621.         avformat_close_input(&cur_avf_saved);
  622.     }
  623.     return ret;
  624. }
  625.  
  626. #define OFFSET(x) offsetof(ConcatContext, x)
  627. #define DEC AV_OPT_FLAG_DECODING_PARAM
  628.  
  629. static const AVOption options[] = {
  630.     { "safe", "enable safe mode",
  631.       OFFSET(safe), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, DEC },
  632.     { "auto_convert", "automatically convert bitstream format",
  633.       OFFSET(auto_convert), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, DEC },
  634.     { NULL }
  635. };
  636.  
  637. static const AVClass concat_class = {
  638.     .class_name = "concat demuxer",
  639.     .item_name  = av_default_item_name,
  640.     .option     = options,
  641.     .version    = LIBAVUTIL_VERSION_INT,
  642. };
  643.  
  644.  
  645. AVInputFormat ff_concat_demuxer = {
  646.     .name           = "concat",
  647.     .long_name      = NULL_IF_CONFIG_SMALL("Virtual concatenation script"),
  648.     .priv_data_size = sizeof(ConcatContext),
  649.     .read_probe     = concat_probe,
  650.     .read_header    = concat_read_header,
  651.     .read_packet    = concat_read_packet,
  652.     .read_close     = concat_read_close,
  653.     .read_seek2     = concat_seek,
  654.     .priv_class     = &concat_class,
  655. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement