[FFmpeg-devel] [PATCH 1/5] concatdec: add support for specifying inpoint of files
Nicolas George
george at nsup.org
Thu Jul 16 11:41:54 CEST 2015
Le tridi 23 messidor, an CCXXIII, Marton Balint a écrit :
> Signed-off-by: Marton Balint <cus at passwd.hu>
> ---
> doc/demuxers.texi | 17 +++++++++++++++++
> libavformat/concatdec.c | 39 ++++++++++++++++++++++++++-------------
> 2 files changed, 43 insertions(+), 13 deletions(-)
>
> diff --git a/doc/demuxers.texi b/doc/demuxers.texi
> index 35a1561..27a9409 100644
> --- a/doc/demuxers.texi
> +++ b/doc/demuxers.texi
> @@ -112,6 +112,23 @@ file is not available or accurate.
> If the duration is set for all files, then it is possible to seek in the
> whole concatenated video.
>
> + at item @code{inpoint @var{timestamp}}
> +In point of the file. When the demuxer opens the file it instantly seeks to the
> +specified timestamp. Seeking is done so that all streams can be presented
> +successfully at In point.
> +
> +This directive works best with intra frame codecs, because for non-intra frame
> +ones you will usually get extra packets before the actual In point and the
> +decoded content will most likely contain frames before In point too.
> +
> +For each file, packets before the file In point will have timestamps less than
> +the calculated start timestamp of the file (negative in case of the first
> +file), and the duration of the files (if not specified by the @code{duration}
> +directive) will be reduced based on their specified In point.
> +
> +Because of potential packets before the specified In point, packet timestamps
> +may overlap between two concatenated files.
> +
> @item @code{stream}
> Introduce a stream in the virtual file.
> All subsequent stream-related directives apply to the last introduced
> diff --git a/libavformat/concatdec.c b/libavformat/concatdec.c
> index e95ff34..de1543a 100644
> --- a/libavformat/concatdec.c
> +++ b/libavformat/concatdec.c
> @@ -41,8 +41,11 @@ typedef struct ConcatStream {
> typedef struct {
> char *url;
> int64_t start_time;
> + int64_t file_start_time;
> + int64_t file_inpoint;
> int64_t duration;
> ConcatStream *streams;
> + int64_t inpoint;
> int nb_streams;
> } ConcatFile;
>
> @@ -142,6 +145,7 @@ static int add_file(AVFormatContext *avf, char *filename, ConcatFile **rfile,
> file->url = url;
> file->start_time = AV_NOPTS_VALUE;
> file->duration = AV_NOPTS_VALUE;
> + file->inpoint = AV_NOPTS_VALUE;
>
> return 0;
>
> @@ -306,8 +310,14 @@ static int open_file(AVFormatContext *avf, unsigned fileno)
> file->start_time = !fileno ? 0 :
> cat->files[fileno - 1].start_time +
> cat->files[fileno - 1].duration;
> + file->file_start_time = (avf->start_time == AV_NOPTS_VALUE) ? 0 : avf->start_time;
> + file->file_inpoint = (file->file_inpoint == AV_NOPTS_VALUE) ? file->file_start_time : file->inpoint;
If I read this correctly, file->file_inpoint is always set.
> if ((ret = match_streams(avf)) < 0)
> return ret;
> + if (file->inpoint != AV_NOPTS_VALUE) {
> + if ((ret = avformat_seek_file(cat->avf, -1, INT64_MIN, file->inpoint, file->inpoint, 0) < 0))
> + return ret;
> + }
> return 0;
> }
>
> @@ -353,20 +363,23 @@ static int concat_read_header(AVFormatContext *avf)
> }
> if ((ret = add_file(avf, filename, &file, &nb_files_alloc)) < 0)
> goto fail;
> - } else if (!strcmp(keyword, "duration")) {
> + } else if (!strcmp(keyword, "duration") || !strcmp(keyword, "inpoint")) {
> char *dur_str = get_keyword(&cursor);
> int64_t dur;
> if (!file) {
> - av_log(avf, AV_LOG_ERROR, "Line %d: duration without file\n",
> - line);
> + av_log(avf, AV_LOG_ERROR, "Line %d: %s without file\n",
> + line, keyword);
> FAIL(AVERROR_INVALIDDATA);
> }
> if ((ret = av_parse_time(&dur, dur_str, 1)) < 0) {
> - av_log(avf, AV_LOG_ERROR, "Line %d: invalid duration '%s'\n",
> - line, dur_str);
> + av_log(avf, AV_LOG_ERROR, "Line %d: invalid %s '%s'\n",
> + line, keyword, dur_str);
> goto fail;
> }
> - file->duration = dur;
> + if (!strcmp(keyword, "duration"))
> + file->duration = dur;
> + else if (!strcmp(keyword, "inpoint"))
> + file->inpoint = dur;
> } else if (!strcmp(keyword, "stream")) {
> if (!avformat_new_stream(avf, NULL))
> FAIL(AVERROR(ENOMEM));
> @@ -428,8 +441,11 @@ static int open_next_file(AVFormatContext *avf)
> ConcatContext *cat = avf->priv_data;
> unsigned fileno = cat->cur_file - cat->files;
>
> - if (cat->cur_file->duration == AV_NOPTS_VALUE)
> + if (cat->cur_file->duration == AV_NOPTS_VALUE) {
> cat->cur_file->duration = cat->avf->duration;
> + if (cat->cur_file->inpoint != AV_NOPTS_VALUE)
... then this test is always true. Is it on purpose ?
> + cat->cur_file->duration -= (cat->cur_file->inpoint - cat->cur_file->file_start_time);
> + }
>
> if (++fileno >= cat->nb_files)
> return AVERROR_EOF;
> @@ -480,7 +496,7 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
> {
> ConcatContext *cat = avf->priv_data;
> int ret;
> - int64_t file_start_time, delta;
> + int64_t delta;
> ConcatStream *cs;
> AVStream *st;
>
> @@ -517,10 +533,7 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
> av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
> av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
>
> - file_start_time = cat->avf->start_time;
> - if (file_start_time == AV_NOPTS_VALUE)
> - file_start_time = 0;
> - delta = av_rescale_q(cat->cur_file->start_time - file_start_time,
> + delta = av_rescale_q(cat->cur_file->start_time - cat->cur_file->file_inpoint,
> AV_TIME_BASE_Q,
> cat->avf->streams[pkt->stream_index]->time_base);
> if (pkt->pts != AV_NOPTS_VALUE)
> @@ -547,7 +560,7 @@ static int try_seek(AVFormatContext *avf, int stream,
> int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
> {
> ConcatContext *cat = avf->priv_data;
> - int64_t t0 = cat->cur_file->start_time - cat->avf->start_time;
> + int64_t t0 = cat->cur_file->start_time - cat->cur_file->file_inpoint;
>
> ts -= t0;
> min_ts = min_ts == INT64_MIN ? INT64_MIN : min_ts - t0;
LGTM apart from that.
Regards,
--
Nicolas George
More information about the ffmpeg-devel
mailing list