diff options
author | Anton Khirnov <anton@khirnov.net> | 2022-08-24 10:27:09 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2023-05-02 10:57:21 +0200 |
commit | c7a852b638b88f129790af31fc47c870c329eaaa (patch) | |
tree | 7792085c28b5df4392859d082518dadc9f58ae38 /libavformat/dv.c | |
parent | 561746591660b456e092324f03d393d6dd9147b1 (diff) | |
download | ffmpeg-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/dv.c')
-rw-r--r-- | libavformat/dv.c | 36 |
1 files changed, 27 insertions, 9 deletions
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, ×tamp); 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; } |