mirror of
https://mirror.skon.top/https://github.com/FFmpeg/FFmpeg
synced 2026-04-20 21:00:41 +08:00
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.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user