av_seek_frame函数
/**
* Seek to the keyframe at timestamp.
* 'timestamp' in 'stream_index'.
*
* @param s media file handle
* @param stream_index If stream_index is (-1), a default
* stream is selected, and timestamp is automatically converted
* from AV_TIME_BASE units to the stream specific time_base.
* @param timestamp Timestamp in AVStream.time_base units
* or, if no stream is specified, in AV_TIME_BASE units.
* @param flags flags which select direction and seeking mode
* @return >= 0 on success
*/
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);
stream_index:用于seek的流索引,-1为默认,一般0为视频流索引,1为音频流索引
timestamp:定位的时间戳,单位以流的time_base为单位,并非毫秒单位的时间戳,因此如果seek,需要结合具体的流的time_base计算对应单位的时间戳
flags:可以设置为按字节,在按时间seek时取该点之前还是之后的关键帧,以及不按关键帧seek等。具体的值有如下几个,可以通过运算符来进行组合
#define AVSEEK_FLAG_BACKWARD 1 ///< seek backward
#define AVSEEK_FLAG_BYTE 2 ///< seeking based on position in bytes
#define AVSEEK_FLAG_ANY 4 ///< seek to any frame, even non-keyframes
#define AVSEEK_FLAG_FRAME 8 ///< seeking based on frame number
ts一般使用AVSEEK_FLAG_BYTE,mp4一般使用AVSEEK_FLAG_ANY、AVSEEK_FLAG_BACKWARD(seek到对应时间戳之前的最后一个关键帧)
下面给出一段实例代码,代码中是对mp4文件按照音频流进行seek,seek的时间点为6秒。
av_register_all();
std::string path = "E:\\media\\test.mp4";
const char *in_filename = path.c_str();
//设置日志级别
av_log_set_level(AV_LOG_INFO);
//通过日志的形式打印
av_log(NULL, AV_LOG_INFO, "\n in_filename = %s\n", in_filename);
//AVFormatContext是描述一个媒体文件或媒体流构成和基本信息的结构体
AVFormatContext *ifmt_ctx = NULL; // 输入文件的demux(解复用)
int videoindex = -1; //视频索引
int audioindex = -1; //音频索引
//1 打开文件,主要探测协议类型,如果是网络文件需要插件网络连接
int ret = avformat_open_input(&ifmt_ctx, in_filename, NULL, NULL);
if (ret < 0)
{
//打印失败原因
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
av_log(NULL, AV_LOG_ERROR, "open %s failed:%s\n", in_filename, buf);
//open believe.mp41 failed:No such file or directory
// goto failed; //error
return;
}
//2 读取媒体的码流信息
ret = avformat_find_stream_info(ifmt_ctx, NULL);
if (ret < 0)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
av_log(NULL, AV_LOG_ERROR, "avformat_find_stream_info %s failed:%s\n", in_filename, buf);
// goto filed; //error ??
return;
}
av_log(NULL, AV_LOG_INFO, "\n==== av_dump_format in_filename:%s ===\n", in_filename);
// 打印输入或输出格式的详细信息
// void av_dump_format(AVFormatContext *ic, int index, const char *url,int is_output);
av_dump_format(ifmt_ctx, 0, in_filename, 0);
av_log(NULL, AV_LOG_INFO, "\n==== av_dump_format finish =======\n\n");
//查看媒体文件的一些信息
//打印媒体的路径
av_log(NULL, AV_LOG_INFO, "media name: %s\n", ifmt_ctx->filename);
//nb_streams媒体流数量
printf("media stream number: %d\n", ifmt_ctx->nb_streams); //media stream number: 2
//bit_rate: 媒体文件的码率,单位为bps
printf("media average ratio:%11d\n", (int64_t)(ifmt_ctx->bit_rate / 1024));
//时间
int total_seconds, hours, minute, second;
//duration: 媒体文件时长,单位微秒
total_seconds = (ifmt_ctx->duration) / AV_TIME_BASE; // 1000us = 1ms, 1000ms = 1秒
hours = total_seconds / 3600;
minute = (total_seconds % 3600) / 60;
second = (total_seconds % 60);
printf("total duration: %02d:%02d:%02d\n", hours, minute, second);
printf("\n");
AVRational in_timebase_v;
AVRational in_timebase_a;
/*
* 老版本通过遍历的方式读取媒体文件视频和音频的信息
* 新版本的FFmpeg新增加了函数av_find_best_stream,也可以取得同样的效果
*/
for (uint32_t i = 0;i < ifmt_ctx->nb_streams;++i)
{
AVStream *in_stream = ifmt_ctx->streams[i]; //音频流,视频流,字幕流
//如果是音频流,则打印音频的信息
if (AVMEDIA_TYPE_AUDIO == in_stream->codecpar->codec_type)
{
in_timebase_a = in_stream->time_base;
printf("----- Audio info timebase:%d/%d\n", in_timebase_a.num, in_timebase_a.den);
//index: 每个流成分在ffmpeg解复用分析后都有唯一的index作为标书
printf("index:%d\n", in_stream->index);
//sample_rate: 音频编码解码器的采样率,单位为HZ
printf("samplerate:%dnHZ\n", in_stream->codecpar->sample_rate);
// codecpar->format:音频采样格式
if (AV_SAMPLE_FMT_FLTP == in_stream->codecpar->format)
{
printf("sampleformat:AV_SAMPLE_FMT_FLTP\n");
}
else if (AV_SAMPLE_FMT_S16P == in_stream->codecpar->format)
{
printf("sampleformat:AV_SAMPLE_FMT_S16P\n");
}
//channels:音频信道数目
printf("channels number:%d\n", in_stream->codecpar->channels);
//codec_id: 音频压缩编码格式
if (AV_CODEC_ID_AAC == in_stream->codecpar->codec_id)
printf("audio codec:AAC\n");
else if (AV_CODEC_ID_MP3 == in_stream->codecpar->codec_id)
printf("audio codec:MP3\n");
else
printf("audio codec_id:%d\n", in_stream->codecpar->codec_id);
// 音频总时长,单位为秒。注意如果把单位放大为毫秒或者微妙,音频总时长跟视频总时长不一定相等的
if (in_stream->duration != AV_NOPTS_VALUE)
{
int duration_audio = (in_stream->duration) * av_q2d(in_stream->time_base);
//将音频总时长转换为时分秒的格式打印到控制台上
printf("audio duration: %02d:%02d:%02d\n",
duration_audio / 3600, (duration_audio % 3600) / 60, (duration_audio % 60));
}
else //如果无效
{
printf("audio duration unknown");
}
printf("\n");
audioindex = i;
}
else if (AVMEDIA_TYPE_VIDEO == in_stream->codec->codec_type)
{
in_timebase_v = in_stream->time_base;
printf("----- Video info:timebase:%d/%d\n", in_timebase_v.num, in_timebase_v.den);
printf("index:%d\n", in_stream->index);
// avg_frame_rate: 视频帧率,单位为fps,表示每秒出现多少帧
printf("fps:%lf\n", av_q2d(in_stream->avg_frame_rate));
if (AV_CODEC_ID_MPEG4 == in_stream->codecpar->codec_id) //视频压缩编码格式
{
printf("video codec:MPEG4\n");
}
else if (AV_CODEC_ID_H264 == in_stream->codecpar->codec_id) //视频压缩编码格式
{
printf("video codec:H264\n");
}
else
{
printf("video codec_id:%d\n", in_stream->codecpar->codec_id);
}
// 视频帧宽度和帧高度
printf("width:%d height:%d\n", in_stream->codecpar->width,
in_stream->codecpar->height);
//视频总时长,单位为秒。注意如果把单位放大为毫秒或者微妙,音频总时长跟视频总时长不一定相等的
if (in_stream->duration != AV_NOPTS_VALUE)
{
int duration_video = (in_stream->duration) * av_q2d(in_stream->time_base);
printf("video duration: %02d:%02d:%02d\n",
duration_video / 3600,
(duration_video % 3600) / 60,
(duration_video % 60)); //将视频总时长转换为时分秒的格式打印到控制台上
}
else
{
printf("video duration unknown");
}
printf("\n");
videoindex = i;
}
}
//3 从文件中读取数据包
AVPacket *pkt = av_packet_alloc();
int pkt_count = 0;
int print_max_count = 1000;
printf("\n-----av_read_frame start\n");
zint64 seekSecValue = 6;
int64_t startTime = seekSecValue / av_q2d(in_timebase_a);
ret = av_seek_frame(ifmt_ctx, audioindex , startTime, AVSEEK_FLAG_BACKWARD|AVSEEK_FLAG_ANY);
while (1)
{
//读取音视频包
ret = av_read_frame(ifmt_ctx, pkt);
if (ret < 0)
{
printf("-----av_read_frame end\n");
break;
}
if (pkt_count++ < print_max_count)
{
if (pkt->stream_index == audioindex)
{
zint64 pts = pkt->pts*1000.0*in_timebase_a.num / in_timebase_a.den;
printf("audio pts: %lld(%lld)\n", pts, pkt->pts);
printf("audio dts: %lld\n", pkt->dts);
printf("audio size: %d\n", pkt->size);
printf("audio pos: %lld\n", pkt->pos);
printf("audio duration: %lf\n\n",
pkt->duration * av_q2d(ifmt_ctx->streams[audioindex]->time_base));
}
else if (pkt->stream_index == videoindex)
{
zint64 pts = pkt->pts*1000.0*in_timebase_v.num / in_timebase_v.den;
printf("video pts: %lld(%lld)\n", pts, pkt->pts);
printf("video dts: %lld\n", pkt->dts);
printf("video size: %d\n", pkt->size);
printf("video pos: %lld\n", pkt->pos);
printf("video duration: %lf\n\n",
pkt->duration * av_q2d(ifmt_ctx->streams[videoindex]->time_base));
}
else {
printf("unknown stream_index:\n", pkt->stream_index);
}
}
av_packet_unref(pkt);
}
if (pkt)
av_packet_free(&pkt);
//4 关闭复用器
//failed:
if (ifmt_ctx)
avformat_close_input(&ifmt_ctx);
输出信息如下图所示:
media stream number: 2
media average ratio: 2155
total duration: 00:19:47
----- Video info:timebase:1/10240
index:0
fps:20.000000
video codec:H264
width:1920 height:1080
video duration: 00:19:47
----- Audio info timebase:1/32000
index:1
samplerate:32000nHZ
sampleformat:AV_SAMPLE_FMT_FLTP
channels number:1
audio codec:AAC
audio duration: 00:19:47
-----av_read_frame start
video pts: 5950(60928)
video dts: 60928
video size: 4136
video pos: 5898643
video duration: 0.050000
audio pts: 5984(191488)
audio dts: 191488
audio size: 395
audio pos: 5903014
audio duration: 0.032000
video pts: 6000(61440)
video dts: 61440
video size: 4319
video pos: 5903409
video duration: 0.050000
audio pts: 6016(192512)
audio dts: 192512
audio size: 275
audio pos: 5907728
audio duration: 0.032000
audio pts: 6048(193536)
audio dts: 193536
audio size: 260
audio pos: 5908003
audio duration: 0.032000
video pts: 6050(61952)
video dts: 61952
video size: 2956
video pos: 5908263
video duration: 0.050000
audio pts: 6080(194560)
audio dts: 194560
audio size: 283
audio pos: 5911219
audio duration: 0.032000
video pts: 6100(62464)
video dts: 62464
video size: 4262
video pos: 5911502
video duration: 0.050000
audio pts: 6112(195584)
audio dts: 195584
audio size: 266
audio pos: 5915764
audio duration: 0.032000
audio pts: 6144(196608)
audio dts: 196608
audio size: 327
audio pos: 5916030
audio duration: 0.032000