[Libav-user] Seeking backward to a key frame within transport stream

rolaoo Gazeta.pl rolaoo at gazeta.pl
Fri Sep 27 08:32:11 CEST 2013


Hello,

few days ago I met a problem with av_seek_frame with AVSEEK_FLAG_BACKWARD.
In case of transport stream and mpeg2 or avc and others it seeks exactly to
a specified time stamp and not to a previous key frame, so the first
decoded frame is past desired time stamp, of course if I am unlucky to seek
not to a key frame which is a most frequent case. I've been googling and it
seems that this is known problem for years. From the user stand point it
looks that av_seek_frame ignores passed flag and uses AVSEEK_FLAG_ANY,
however there's no clear feedback that it has happened. Is any progress,
helper or workaroud on this issue till now (I work with
ffmpeg-20130909-git-b4e1630)?
In meantime I have developed my own workaround which I want to share, maybe
some find it usefull. Instead of typical seek and decode until required
time stamp (a simplified pseudocode below):

av_seek_frame( desired_time_stamp, AVSEEK_FLAG_BACKWARD)
do
{
  demux packet and decode frame
}
while( frame.time_stamp < desired_time_stamp)

I use following approach:

// Seek to desired time stamp
av_seek_frame( desired_time_stamp, AVSEEK_FLAG_BACKWARD)

// try to decode some frame. If decoded frame time stamp is after seek point
// then rewind (seek) once again before desired time stamp.
int round = 0;
long long rewind_time = 1 second
while(true)
{
 demux packet and decode frame
 if(frame.time_stamp < desired_time_stamp)
   break
  ++round
  av_seek_frame( desired_time_stamp - rewind_time * round,
AVSEEK_FLAG_BACKWARD)
  reset decoder
}

// Now we have at least one frame before desired time stamp
// Decode forward up to desired time stamp.
while( frame.time_stamp < desired_time_stamp)
{
  demux packet and decode frame
}

It works pretty well and does not add overhead for non-mpeg demuxers, where
av_seek_frame works as described in documentation. Of course there's a
significant overhead caused by iterative backward seeking. In this
pseudocode I choosed to rewind one second. The obvious rewind time is gop
size, but I found gop_size as unreliable (e.g. some of my test streams have
key frame distance equal to 96, however gop_size is 12). Also GOP size may
vary within the same file. Now my approach is to track gop size
during decoding the file since any fixed revind value is IMHO not good.
Another useful trick is to set AVCodecContext::flags2 to
CODEC_FLAG2_SHOW_ALL. It gives faster decoder output so the need for rewind
can be detected quicker, however a special care must be taken to not to
display corrupted frames.
Any comments/improvements are welcome.

best regards

Remigiusz
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://ffmpeg.org/pipermail/libav-user/attachments/20130927/59646898/attachment.html>


More information about the Libav-user mailing list