[FFmpeg-devel] [PATCH 6/6] concat: support seeking inside sub-files [WIP].
Nicolas George
george at nsup.org
Fri Feb 21 20:50:18 CET 2014
From: Nicolas George <nicolas.george at normalesup.org>
Signed-off-by: Nicolas George <george at nsup.org>
---
libavformat/concatdec.c | 112 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 102 insertions(+), 10 deletions(-)
diff --git a/libavformat/concatdec.c b/libavformat/concatdec.c
index 979499a..9d2c73e 100644
--- a/libavformat/concatdec.c
+++ b/libavformat/concatdec.c
@@ -19,16 +19,21 @@
*/
#include "libavutil/avstring.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
#include "avformat.h"
#include "internal.h"
#include "url.h"
+#include "libavutil/timestamp.h"
+
typedef struct {
char *url;
int64_t start_time;
+ int64_t delta;
int64_t duration;
+ int64_t seek_time;
} ConcatFile;
typedef struct {
@@ -115,6 +120,8 @@ 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->seek_time = AV_NOPTS_VALUE;
+ file->delta = AV_NOPTS_VALUE;
return 0;
@@ -149,6 +156,21 @@ static int open_file(AVFormatContext *avf, unsigned fileno)
file->start_time = !fileno ? 0 :
cat->files[fileno - 1].start_time +
cat->files[fileno - 1].duration;
+ if (file->delta == AV_NOPTS_VALUE) {
+ int64_t first_pts = cat->avf->start_time;
+ if (file->seek_time != AV_NOPTS_VALUE)
+ first_pts = file->seek_time;
+ file->delta = file->start_time - first_pts;
+ }
+ if (file->seek_time != AV_NOPTS_VALUE) {
+ ret = avformat_seek_file(cat->avf, -1, 0, file->seek_time,
+ file->seek_time, 0);
+ if (ret < 0) {
+ av_log(avf, AV_LOG_ERROR, "Error seeking in '%s': %s\n",
+ file->url, av_err2str(ret));
+ return ret;
+ }
+ }
return 0;
}
@@ -207,6 +229,20 @@ static int concat_read_header(AVFormatContext *avf)
FAIL(ret);
}
file->duration = dur;
+ } else if (!strcmp(keyword, "seek")) {
+ char *time_str = get_keyword(&cursor);
+ int64_t time;
+ if (!file) {
+ av_log(avf, AV_LOG_ERROR, "Line %d: duration without file\n",
+ line);
+ FAIL(AVERROR_INVALIDDATA);
+ }
+ if ((ret = av_parse_time(&time, time_str, 1)) < 0) {
+ av_log(avf, AV_LOG_ERROR, "Line %d: invalid seek time '%s'\n",
+ line, time_str);
+ FAIL(ret);
+ }
+ file->seek_time = time;
} else if (!strcmp(keyword, "ffconcat")) {
char *ver_kw = get_keyword(&cursor);
char *ver_val = get_keyword(&cursor);
@@ -275,11 +311,71 @@ static int open_next_file(AVFormatContext *avf)
return open_file(avf, fileno);
}
+static uint8_t *get_skip_side_data(AVPacket *pkt)
+{
+ uint8_t *side_data;
+
+ /* TODO use if already present */
+ side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
+ return side_data;
+}
+
+static int alter_packet_ts(AVFormatContext *avf, AVPacket *pkt)
+{
+ ConcatContext *cat = avf->priv_data;
+ ConcatFile *file = cat->cur_file;
+ AVStream *st = cat->avf->streams[pkt->stream_index];
+ AVRational tb = st->time_base;
+ AVRational rtb = { 1, st->codec->sample_rate };
+ int64_t real_pts = pkt->pts;
+ int64_t delta = av_rescale_q(file->delta, AV_TIME_BASE_Q, tb);
+ int64_t skip;
+ uint8_t *side_data;
+
+ if (pkt->pts != AV_NOPTS_VALUE)
+ pkt->pts += delta;
+ if (pkt->dts != AV_NOPTS_VALUE)
+ pkt->dts += delta;
+
+ if (file->seek_time != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE &&
+ av_rescale_q(real_pts, tb, AV_TIME_BASE_Q) < file->seek_time) {
+ switch (st->codec->codec_type) {
+
+ case AVMEDIA_TYPE_VIDEO:
+ pkt->flags |= AV_PKT_FLAG_DISCARD;
+ pkt->pts = file->start_time;
+ pkt->dts = AV_NOPTS_VALUE;
+ break;
+
+ case AVMEDIA_TYPE_AUDIO:
+ if (!rtb.den) {
+ av_log(cat->avf, AV_LOG_ERROR,
+ "Sample rate not set, accurate seeking impossible");
+ return 0;
+ }
+ skip = av_rescale_q(file->seek_time, AV_TIME_BASE_Q, rtb)
+ - av_rescale_q(real_pts, tb, rtb);
+ if (!(side_data = get_skip_side_data(pkt)))
+ return AVERROR(ENOMEM);
+ skip = av_clip(skip, 0, INT_MAX);
+ skip = FFMAX(skip, AV_RL32(side_data));
+ AV_WL32(side_data, skip);
+ pkt->flags |= AV_PKT_FLAG_DISCARD;
+ break;
+
+ default:
+ av_log(avf, AV_LOG_WARNING,
+ "Frame-accurate seeking not implemented for %s streams\n",
+ av_get_media_type_string(st->codec->codec_type));
+ }
+ }
+ return 0;
+}
+
static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
{
ConcatContext *cat = avf->priv_data;
int ret;
- int64_t delta;
while (1) {
if ((ret = av_read_frame(cat->avf, pkt)) != AVERROR_EOF ||
@@ -288,15 +384,11 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
}
if (ret < 0)
return ret;
-
- delta = av_rescale_q(cat->cur_file->start_time - cat->avf->start_time,
- AV_TIME_BASE_Q,
- cat->avf->streams[pkt->stream_index]->time_base);
- if (pkt->pts != AV_NOPTS_VALUE)
- pkt->pts += delta;
- if (pkt->dts != AV_NOPTS_VALUE)
- pkt->dts += delta;
- return ret;
+ if ((ret = alter_packet_ts(avf, pkt)) < 0) {
+ av_free_packet(pkt);
+ return ret;
+ }
+ return 0;
}
static void rescale_interval(AVRational tb_in, AVRational tb_out,
--
1.8.5.3
More information about the ffmpeg-devel
mailing list