mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2026-06-19 19:03:00 +02:00
concatdec: add support for specifying inpoint of files
Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Marton Balint <cus@passwd.hu>
This commit is contained in:
committed by
Michael Niedermayer
parent
53f2ef2c4a
commit
7ff0137a1f
@@ -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.
|
||||
|
||||
@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
|
||||
|
||||
+26
-13
@@ -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 ((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)
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user