[FFmpeg-trac] #941(avformat:open): Seek problems with ogg decoder
FFmpeg
trac at avcodec.org
Sat Feb 4 05:58:47 CET 2012
#941: Seek problems with ogg decoder
------------------------------------+------------------------------------
Reporter: DonMoir | Owner:
Type: defect | Status: open
Priority: normal | Component: avformat
Version: git-master | Resolution:
Keywords: ogg seek | Blocked By:
Blocking: | Reproduced by developer: 1
Analyzed by developer: 0 |
------------------------------------+------------------------------------
Comment (by DonMoir):
Creating the index_entries fixed the BuckBunny sample. The code I use for
this is here and it begins to fix ogg_read_seek problems for all ogg
files.
{{{
static void check_index_entries (
// Creates the index_entries prior to seeking if needbe.
cFFmpegPlayer* pPlayer, uint32_t streamIndex, int64_t timestamp, struct
ogg_stream* pOggStream)
{
AVFormatContext *pFmtCtx = pPlayer->pFormatCtx;
AVPacket packet;
AVStream* pStream;
int lastIdx;
if (pFmtCtx == NULL || streamIndex >= pFmtCtx->nb_streams)
return;
pStream = pFmtCtx->streams [streamIndex];
lastIdx = pStream->nb_index_entries - 1;
if (lastIdx >= 0 &&
(pStream->index_entries [lastIdx].flags & AVINDEX_KEYFRAME) &&
pStream->index_entries [lastIdx].timestamp >= timestamp)
return;
// I am assuming we don't need to seek to the lastKnownTime to start
reading because
// the file position will be before here or past it. If it is past it
then the entry
// would have already been created and we would not be here :) This
may require a
// little more thought but this doesn't hurt anything.
while (!pPlayer->bAllDone && !pPlayer->m_bThreadStopSeek)
{
if (pOggStream)
pOggStream->keyframe_seek = 1;
if (p_av_read_frame (pFmtCtx,&packet))
break;
if (packet.stream_index == streamIndex)
{
lastIdx = pStream->nb_index_entries - 1;
if (lastIdx >= 0 &&
(pStream->index_entries [lastIdx].flags & AVINDEX_KEYFRAME)
&&
pStream->index_entries [lastIdx].timestamp >= timestamp)
{
p_av_free_packet (&packet);
break;
}
}
p_av_free_packet (&packet);
}
}
}}}
Note this code in the above just after the while statement:
{{{
if (pOggStream)
pOggStream->keyframe_seek = 1;
}}}
This just speeds up the check_index_entries function a bit, but still
there are going to faster ways to create the index_entries for ogg.
I mentioned I had some other odd behavior with some ogg files. For my app
this showed up as frames not displaying for some time after a seek. In
other apps you will see other odd behavior like incomplete frames, audio
out of sync, or just weirdness.
Here's the ogg_read_seek function as it stands in ffmpeg:
{{{
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 == AVMEDIA_TYPE_VIDEO
&& !(flags & AVSEEK_FLAG_ANY))
os->keyframe_seek = 1;
ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
os = ogg->streams + stream_index;
if (ret < 0)
os->keyframe_seek = 0;
return ret;
}
}}}
Note this code at the bottom of the ogg_read_seek function:
{{{
if (ret < 0)
os->keyframe_seek = 0;
}}}
os->keyframe_seek needs to be set back to 0 regardless of the return
value. After I changed this all the remaining problems went away and I can
now seek perfect on all the ogg files I have.
In summary 3 things need to be fixed for ogg_read_seek:
1) create the index entries prior to seeking - without this seeking will
be bad - hopefully someone will come up with a more efficient solution
then the solution I am using.
2) make sure os->keyframe_seek is set back to 0 always and don't depend on
any return value. This fixed all the remaining weirdness.
3) call ogg_reset after the seek - this is not perfect and there is
something more with this but without this - the first packet read will
contain stale information as mentioned above. You will still get
AV_NOPTS_VALUE one the first read which is not right either. I think
calling ogg_reset and setting the lastpts and lastdts in the ogg_stream
may do it.
--
Ticket URL: <https://ffmpeg.org/trac/ffmpeg/ticket/941#comment:5>
FFmpeg <http://ffmpeg.org>
FFmpeg issue tracker
More information about the FFmpeg-trac
mailing list