播放器进度条,ffmpeg中av_seek_frame()的使用方法

av_seek_frame有两种使用方法
1.当参数stream_index为-1时,会选择一个默认流,时间戳会从以AV_TIME_BASE为单位

//seek到1.25秒
double sec = 1.25;//1.25秒
int64_t timestamp = sec * AV_TIME_BASE;
av_seek_frame(pFormatCtx,-1,timestamp,AVSEEK_FLAG_BACKWARD);

2.当参数stream_index为视频流的索引时,参数timestamp就表示AVPacket中的pts时间戳

double sec = 1.25;
int64_t pts = sec / av_q2d(pFormatCtx->streams[vStreamIndex]->time_base);
av_seek_frame(pFormatCtx,vStreamIndex,pts,AVSEEK_FLAG_BACKWARD);

因为packet播放时刻值:sec(单位秒) = packet.pts × av_q2d(stream.time_base);
所以pts = sec / av_q2d(pFormatCtx->streams[vStreamIndex]->time_base);

关于参数flags值:

AVSEEK_FLAG_BACKWARD  是seek到请求的时间戳之前最近的关键帧

AVSEEK_FLAG_BYTE             是基于字节位置的查找 

AVSEEK_FLAG_ANY               是可以seek到任意帧,注意不一定是关键帧,因此使用时可能会导致花屏    

AVSEEK_FLAG_FRAME         是基于帧数量快进 

当我们使用AVSEEK_FLAG_BACKWARD 模拟播放器拖动进度条定位图像时,有时发现一段时间内都显示相同的画面,那是因为这段时间都seek到了相同的关键帧(I帧),如果换成AVSEEK_FLAG_ANY 又会导致花屏,那是因为p帧依赖前面的I帧或p帧,B帧依赖前后的I帧或p帧。所以当seek到p帧或B帧时由于没有解码I帧或p帧,因此数据是缺损的导致花屏。
我的解决方法是使用AVSEEK_FLAG_BACKWARD seek到I帧时,再继续解码循环直到AVPacket.pts >= av_seek_frame第三个参数传入的值(要考虑有的视频AVPacket.pts为负数)

你可能感兴趣的:(ffmpeg,av_seek_frame)