[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