oggdec: Seek to keyframes

Originally committed as revision 22463 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
David Conrad 2010-03-11 07:18:00 +00:00
parent 873d117e4b
commit d8b91fae1d
2 changed files with 34 additions and 3 deletions

View File

@ -531,9 +531,10 @@ ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
struct ogg_stream *os;
int idx = -1;
int pstart, psize;
int64_t fpos;
int64_t fpos, pts, dts;
//Get an ogg packet
retry:
do{
if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
return AVERROR(EIO);
@ -542,13 +543,21 @@ ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
ogg = s->priv_data;
os = ogg->streams + idx;
// pflags might not be set until after this
pts = ogg_calc_pts(s, idx, &dts);
if (os->keyframe_seek && !(os->pflags & PKT_FLAG_KEY))
goto retry;
os->keyframe_seek = 0;
//Alloc a pkt
if (av_new_packet (pkt, psize) < 0)
return AVERROR(EIO);
pkt->stream_index = idx;
memcpy (pkt->data, os->buf + pstart, psize);
pkt->pts = ogg_calc_pts(s, idx, &pkt->dts);
pkt->pts = pts;
pkt->dts = dts;
pkt->flags = os->pflags;
pkt->duration = os->pduration;
pkt->pos = fpos;
@ -577,6 +586,7 @@ ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
int64_t pos_limit)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + stream_index;
ByteIOContext *bc = s->pb;
int64_t pts = AV_NOPTS_VALUE;
int i;
@ -586,6 +596,8 @@ ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
while (url_ftell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
if (i == stream_index) {
pts = ogg_calc_pts(s, i, NULL);
if (os->keyframe_seek && !(os->pflags & PKT_FLAG_KEY))
pts = AV_NOPTS_VALUE;
}
if (pts != AV_NOPTS_VALUE)
break;
@ -594,6 +606,24 @@ ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
return pts;
}
static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + stream_index;
int ret;
// Try seeking to a keyframe first. If this fails (very possible),
// av_seek_frame will fall back to ignoring keyframes
if (s->streams[stream_index]->codec->codec_type == CODEC_TYPE_VIDEO
&& !(flags & AVSEEK_FLAG_ANY))
os->keyframe_seek = 1;
ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
if (ret < 0)
os->keyframe_seek = 0;
return ret;
}
static int ogg_probe(AVProbeData *p)
{
if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
@ -612,7 +642,7 @@ AVInputFormat ogg_demuxer = {
ogg_read_header,
ogg_read_packet,
ogg_read_close,
NULL,
ogg_read_seek,
ogg_read_timestamp,
.extensions = "ogg",
.metadata_conv = ff_vorbiscomment_metadata_conv,

View File

@ -75,6 +75,7 @@ struct ogg_stream {
uint8_t segments[255];
int incomplete; ///< whether we're expecting a continuation in the next page
int page_end; ///< current packet is the last one completed in the page
int keyframe_seek;
void *private;
};