summaryrefslogtreecommitdiff
path: root/libavformat
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2022-08-24 10:27:09 +0200
committerAnton Khirnov <anton@khirnov.net>2023-05-02 10:57:21 +0200
commitc7a852b638b88f129790af31fc47c870c329eaaa (patch)
tree7792085c28b5df4392859d082518dadc9f58ae38 /libavformat
parent561746591660b456e092324f03d393d6dd9147b1 (diff)
downloadffmpeg-c7a852b638b88f129790af31fc47c870c329eaaa.tar.gz
lavf/dv: do not set video timebase more than once
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.
Diffstat (limited to 'libavformat')
-rw-r--r--libavformat/avidec.c22
-rw-r--r--libavformat/dv.c36
-rw-r--r--libavformat/dv.h2
3 files changed, 44 insertions, 16 deletions
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 = 25000000;
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->pts = c->frames;
+ pkt->pts = c->next_pts_video;
+ pkt->duration = av_rescale_q(1, c->sys->time_base, c->vst->time_base);
+
+ c->next_pts_video += pkt->duration;
}
c->frames++;
@@ -472,28 +477,34 @@ int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt,
}
static int64_t dv_frame_offset(AVFormatContext *s, DVDemuxContext *c,
- int64_t timestamp, int flags)
+ int64_t *timestamp)
{
// FIXME: sys may be wrong if last dv_read_packet() failed (buffer is junk)
FFFormatContext *const si = ffformatcontext(s);
const int frame_size = c->sys->frame_size;
+ int64_t frame_count = av_rescale_q(*timestamp, c->vst->time_base, c->sys->time_base);
int64_t offset;
int64_t size = avio_size(s->pb) - si->data_offset;
int64_t max_offset = ((size - 1) / frame_size) * frame_size;
- offset = frame_size * timestamp;
+ offset = frame_size * frame_count;
if (size >= 0 && offset > max_offset)
offset = max_offset;
else if (offset < 0)
offset = 0;
+ *timestamp = av_rescale_q(offset / frame_size, c->sys->time_base, c->vst->time_base);
+
return offset + si->data_offset;
}
-void ff_dv_offset_reset(DVDemuxContext *c, int64_t frame_offset)
+void ff_dv_ts_reset(DVDemuxContext *c, int64_t ts)
{
- c->frames = frame_offset;
+ c->frames = !c->sys ? 0 :
+ av_rescale_q(ts, c->vst->time_base, c->sys->time_base);
+ c->next_pts_video = ts;
+
c->audio_pkt[0].size = c->audio_pkt[1].size = 0;
c->audio_pkt[2].size = c->audio_pkt[3].size = 0;
}
@@ -618,12 +629,19 @@ static int dv_read_seek(AVFormatContext *s, int stream_index,
{
RawDVContext *r = s->priv_data;
DVDemuxContext *c = &r->dv_demux;
- int64_t offset = dv_frame_offset(s, c, timestamp, flags);
+ int64_t offset;
+
+ // seek using the video stream
+ if (stream_index != c->vst->index)
+ timestamp = av_rescale_q(timestamp, s->streams[stream_index]->time_base,
+ c->vst->time_base);
+
+ offset = dv_frame_offset(s, c, &timestamp);
if (avio_seek(s->pb, offset, SEEK_SET) < 0)
return -1;
- ff_dv_offset_reset(c, offset / c->sys->frame_size);
+ ff_dv_ts_reset(c, timestamp);
return 0;
}
diff --git a/libavformat/dv.h b/libavformat/dv.h
index efced6ccf0..d21ea19e02 100644
--- a/libavformat/dv.h
+++ b/libavformat/dv.h
@@ -34,6 +34,6 @@ typedef struct DVDemuxContext DVDemuxContext;
DVDemuxContext* avpriv_dv_init_demux(AVFormatContext* s);
int avpriv_dv_get_packet(DVDemuxContext*, AVPacket *);
int avpriv_dv_produce_packet(DVDemuxContext*, AVPacket*, uint8_t*, int, int64_t);
-void ff_dv_offset_reset(DVDemuxContext *c, int64_t frame_offset);
+void ff_dv_ts_reset(DVDemuxContext *c, int64_t ts_video);
#endif /* AVFORMAT_DV_H */