id	summary	reporter	owner	description	type	status	priority	component	version	resolution	keywords	cc	blockedby	blocking	reproduced	analyzed
1189	Seeking to timestamp 0 without AVSEEK_FLAG_BACKWARD results in seek to timestamp of 12	mbradshaw		"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);
}
}}}"	enhancement	closed	minor	documentation	git-master	fixed					0	0
