Current code will call avpriv_set_pts_info() for each video frame,
possibly setting a different timebase if the stream framerate changes.
This violates API conventions, as the timebase is supposed to stay
constant after stream creation.
Change the demuxer to set a single timebase that is fine enough to
handle all supported DV framerates.
The seek tests change slightly because the new timebase is more
granular.
---
libavcodec/dv.h | 3 +++
libavformat/avidec.c | 22 +--
libavformat/dv.c | 36 +++
libavformat/dv.h | 2 +-
tests/ref/seek/lavf-dv| 16 +++---
tests/ref/seek/vsynth_lena-dv | 24 ++---
tests/ref/seek/vsynth_lena-dv-411 | 24 ++---
tests/ref/seek/vsynth_lena-dv-50 | 24 ++---
8 files changed, 91 insertions(+), 60 deletions(-)
diff --git a/libavcodec/dv.h b/libavcodec/dv.h
index 29f97b6089..b473bdc992 100644
--- a/libavcodec/dv.h
+++ b/libavcodec/dv.h
@@ -60,6 +60,9 @@ enum DVPackType {
*/
#define DV_MAX_FRAME_SIZE 576000
+// LCM of video framerate numerators
+#define DV_TIMESCALE_VIDEO 6
+
/**
* maximum number of blocks per macroblock in any DV format
*/
diff --git a/libavformat/avidec.c b/libavformat/avidec.c
index 7a3fad6392..00bd7a98a9 100644
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@ -1869,13 +1869,20 @@ static int avi_read_seek(AVFormatContext *s, int
stream_index,
st= s->streams[stream_index];
sti = ffstream(st);
ast = st->priv_data;
-index = av_index_search_timestamp(st,
- timestamp * FFMAX(ast->sample_size, 1),
- flags);
+
+if (avi->dv_demux) {
+// index entries are in the AVI scale/rate timebase, which does
+// not match DV demuxer's stream timebase
+timestamp = av_rescale_q(timestamp, st->time_base,
+ (AVRational){ ast->scale, ast->rate });
+} else
+timestamp *= FFMAX(ast->sample_size, 1);
+
+index = av_index_search_timestamp(st, timestamp, flags);
if (index < 0) {
if (sti->nb_index_entries > 0)
av_log(s, AV_LOG_DEBUG, "Failed to find timestamp %"PRId64 " in
index %"PRId64 " .. %"PRId64 "\n",
- timestamp * FFMAX(ast->sample_size, 1),
+ timestamp,
sti->index_entries[0].timestamp,
sti->index_entries[sti->nb_index_entries - 1].timestamp);
return AVERROR_INVALIDDATA;
@@ -1883,7 +1890,7 @@ static int avi_read_seek(AVFormatContext *s, int
stream_index,
/* find the position */
pos = sti->index_entries[index].pos;
-timestamp = sti->index_entries[index].timestamp / FFMAX(ast->sample_size,
1);
+timestamp = sti->index_entries[index].timestamp;
av_log(s, AV_LOG_TRACE, "XX %"PRId64" %d %"PRId64"\n",
timestamp, index, sti->index_entries[index].timestamp);
@@ -1898,11 +1905,14 @@ static int avi_read_seek(AVFormatContext *s, int
stream_index,
/* Feed the DV video stream version of the timestamp to the */
/* DV demux so it can synthesize correct timestamps.*/
-ff_dv_offset_reset(avi->dv_demux, timestamp);
+ff_dv_ts_reset(avi->dv_demux,
+ av_rescale_q(timestamp, (AVRational){ ast->scale,
ast->rate },
+st->time_base));
avi->stream_index = -1;
return 0;
}
+timestamp /= FFMAX(ast->sample_size, 1);
pos_min = pos;
for (i = 0; i < s->nb_streams; i++) {
diff --git a/libavformat/dv.c b/libavformat/dv.c
index ffed1a7a90..9888c10b48 100644
--- a/libavformat/dv.c
+++ b/libavformat/dv.c
@@ -69,6 +69,8 @@ struct DVDemuxContext {
uint8_t audio_buf[4][8192];
int ach;
int frames;
+
+int64_t next_pts_video;
};
static inline uint16_t dv_audio_12to16(uint16_t sample)
@@ -314,8 +316,6 @@ static int dv_extract_video_info(DVDemuxContext *c, const
uint8_t *frame)
par = c->vst->codecpar;
-avpriv_set_pts_info(c->vst, 64, c->sys->time_base.num,
-c->sys->time_base.den);
c->vst->avg_frame_rate = av_inv_q(c->vst->time_base);
/* finding out SAR is a little bit messy */
@@ -360,6 +360,8 @@ static int dv_init_demux(AVFormatContext *s, DVDemuxContext
*c)
c->vst->codecpar->bit_rate = 2500;
c->vst->start_time= 0;
+avpriv_set_pts_info(c->vst, 64, 1, DV_TIMESCALE_VIDEO);
+
/* Audio streams are added later as they are encountered. */
s->ctx_flags |= AVFMTCTX_NOHEADER;
@@ -463,7 +465,10 @@ int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket
*pkt,
pkt->size = size;
pkt->flags |= AV_PKT_FLAG_KEY;
pkt->stream_index = c->vst->index;
-pkt-