[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