Reputation: 1265
I am writing a simple audio player with ffmpeg
ver.4.4.4, and I want to seek to specific timestamp of the audio media (a MP3 file).
Here is my code.
I am using avformat_seek_file()
with flags of AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD
, and when I set seek_pos
to 10 second when it is playing frames of 3rd second, it seemed NOT jump to the 10th second, it only played the audios after 3rd second!
Then I added the code skipping/discarding the packets whose pts is before the seek position. This time, it loops in the if (curr_s < seek_ts)
, not going to 10th seconds.
It seemed NO keyframe
at 10th second.
void decode_func(...)
{
while (1) {
if (av_read_frame(pfmtctx, packet) < 0) {
avcodec_flush_buffers(pcodectx);
printf("Got end of media, breaking\n");
break;
}
/**
* Discard the packet of pts before seek position
*/
curr_s = packet->pts * av_q2d(pfmtctx->streams[stream]->time_base);
if (seek_ts) {
if (curr_s < seek_ts) {
avcodec_flush_buffers(pcodectx);
av_frame_unref(pFrame);
continue;
} else {
seek_ts = 0;
}
}
if (seek_req) {
int64_t seek_abs;
seek_req = 0;
seek_abs = (seek_pos)*AV_TIME_BASE;
printf("Seek to %lld, pts: %lld\n", seek_abs, packet->pts;
if (seek_abs < 0) {
seek_abs = 0;
}
if (avformat_seek_file(pfmtctx, -1, INT64_MIN, seek_abs, INT64_MAX, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD) >= 0) {
avcodec_flush_buffers(pcodectx);
seek_ts = seek_abs;
continue;
} else {
printf("Failed to seek to %lld\n", seek_abs);
seek_ts = 0;
}
}
res = avcodec_send_packet(pcodectx, packet);
while (res >= 0) {
res = avcodec_receive_frame(pcodectx, pFrame);
if (res == AVERROR(EAGAIN)) {
break;
} else if (res == AVERROR_EOF) {
break;
} else if (res >= 0) {
/// Processing decoded frame
}
av_frame_unref(frame);
}
}
So, how can I precisely (almost) seek to a timestamp with FFMPEG?
Upvotes: 1
Views: 49