[FFmpeg-trac] #1189(undetermined:new): Seeking to timestamp 0 without AVSEEK_FLAG_BACKWARD results in seek to timestamp of 12

FFmpeg trac at avcodec.org
Wed Apr 11 21:54:21 CEST 2012


#1189: Seeking to timestamp 0 without AVSEEK_FLAG_BACKWARD results in seek to
timestamp of 12
-------------------------------------+-------------------------------------
               Reporter:  mbradshaw  |                  Owner:
                   Type:  defect     |                 Status:  new
               Priority:  normal     |              Component:
                Version:  git-       |  undetermined
  master                             |               Keywords:
             Blocked By:             |               Blocking:
Reproduced by developer:  0          |  Analyzed by developer:  0
-------------------------------------+-------------------------------------
 Trying to seek to a timestamp 0 without AVSEEK_FLAG_BACKWARD causes the
 stream to seek to a timestamp of 12. Adding the flag AVSEEK_FLAG_BACKWARD
 fixes this and results in seeking to the first frame.

 Consequently, this makes the call `avformat_seek_file(formatContext, 0, 0,
 0, 0)` seek to a timestamp of 12 instead of 0 as well.

 If you run the program below, all the frames will be saved out in the
 correct order. However, if AVSEEK_FLAG_BACKWARD is removed, the first 11
 frames are skipped (fyi the first frame is a repeat frame, so 12 with the
 repeat).

 The attached video sample is an MOV container with with one mpeg2video
 stream. It was created from a source H264 sample with ffmpeg with the
 command:
 `ffmpeg -i TimeCode.mov -an -vcodec mpeg2video mpeg2.mov`

 I do not believe AVSEEK_FLAG_BACKWARD should be necessary here in this
 case. I believe this behavior shows up in other files as well (that is,
 seeking to a ts of 0 without AVSEEK_FLAG_BACKWARD ends up skipping the
 first keyframe and seeking to the second keyframe), but haven't confirmed
 this.

 {{{
 #include <fstream>
 #include <iostream>

 extern "C"
 {
 #include <avcodec.h>
 #include <avformat.h>
 #include <swscale.h>
 };

 void saveFrame(const AVFrame* frame, int width, int height, int
 frameNumber)
 {
     char filename[32];
     sprintf(filename, "frame%d.ppm", frameNumber);
     std::ofstream file(filename, std::ios_base::binary |
 std::ios_base::trunc | std::ios_base::out);

     if (!file.good())
     {
         throw std::runtime_error("Unable to open the file to write the
 frame");
     }

     file << "P5\n" << width << '\n' << height << "\n255\n";

     for (int i = 0; i < height; ++i)
     {
         file.write((char*)(frame->data[0] + i * frame->linesize[0]),
 width);
     }
 }

 int main()
 {
     av_register_all();
     AVFrame* frame = avcodec_alloc_frame();
     if (!frame)
     {
         return 1;
     }

     AVFormatContext* formatContext = NULL;
     if (avformat_open_input(&formatContext, "mpeg2.mov", NULL, NULL) != 0)
     {
         av_free(frame);
         return 1;
     }

     if (avformat_find_stream_info(formatContext, NULL) < 0)
     {
         av_free(frame);
         av_close_input_file(formatContext);
         return 1;
     }

     if (formatContext->nb_streams < 1 ||
 formatContext->streams[0]->codec->codec_type != AVMEDIA_TYPE_VIDEO)
     {
         av_free(frame);
         av_close_input_file(formatContext);
         return 1;
     }

     AVStream* stream = formatContext->streams[0];
     AVCodecContext* codecContext = stream->codec;

     codecContext->codec = avcodec_find_decoder(codecContext->codec_id);
     if (codecContext->codec == NULL)
     {
         av_free(frame);
         avcodec_close(codecContext);
         av_close_input_file(formatContext);
         return 1;
     }
     else if (avcodec_open2(codecContext, codecContext->codec, NULL) != 0)
     {
         av_free(frame);
         avcodec_close(codecContext);
         av_close_input_file(formatContext);
         return 1;
     }

     avcodec_flush_buffers(codecContext);

     std::cout << "Seek successful? " << (av_seek_frame(formatContext, -1,
 0, AVSEEK_FLAG_BACKWARD) >= 0) << std::endl;

     AVPacket packet;
     av_init_packet(&packet);

     std::ofstream stats("stats.txt");

     int frameNumber = 0;
     while (av_read_frame(formatContext, &packet) == 0)
     {
         std::cout << "key packet? " << (packet.flags & AV_PKT_FLAG_KEY) <<
 std::endl;
         if (packet.stream_index == stream->index)
         {
             int frameFinished = 0;
             avcodec_decode_video2(codecContext, frame, &frameFinished,
 &packet);

             if (frameFinished)
             {
                 saveFrame(frame, codecContext->width,
 codecContext->height, frameNumber++);
                 stats << "repeat: " << frame->repeat_pict << "\tkeyframe:
 " << frame->key_frame << "\tbest_ts: " << frame->best_effort_timestamp <<
 '\n';
             }
         }
     }

     av_free_packet(&packet);

     if (codecContext->codec->capabilities & CODEC_CAP_DELAY)
     {
         av_init_packet(&packet);
         int frameFinished = 0;
         int result = 0;
         while ((result = avcodec_decode_video2(codecContext, frame,
 &frameFinished, &packet)) >= 0 && frameFinished)
         {
             if (frameFinished)
             {
                 saveFrame(frame, codecContext->width,
 codecContext->height, frameNumber++);
                 stats << "repeat: " << frame->repeat_pict << "\tkeyframe:
 " << frame->key_frame << "\tbest_ts: " << frame->best_effort_timestamp <<
 '\n';
             }
         }
     }

     av_free(frame);
     avcodec_close(codecContext);
     av_close_input_file(formatContext);
 }
 }}}

-- 
Ticket URL: <https://ffmpeg.org/trac/ffmpeg/ticket/1189>
FFmpeg <http://ffmpeg.org>
FFmpeg issue tracker


More information about the FFmpeg-trac mailing list