通过捕获SDL_KEYDOWN按键按下事件,并通过标志位判断当前的键位SDL_Event::SDL_KeyboardEvent::SDL_Keysym::SDL_Keycode为SDLK_LEFT或SDLK_RIGHT,以此来确定是向前跳转还是向后跳转。
switch (_event.type) {
case SDL_KEYDOWN:
switch (_event.key.keysym.sym) {
case SDLK_LEFT:
avc->set_seek_pos(-SEEK_POS_CHANGE);
break;
case SDLK_RIGHT:
avc->set_seek_pos(SEEK_POS_CHANGE);
break;
default:
break;
}
}
使用一个标志位seek_pos来表示跳转到文件中的位置;每次发生跳转时,先更新当前文件位置,将seek_pos加上上次跳转时时间和当前时间的时间差作为最新的seek_pos;然后加上当前的跳转变化量,作为跳转到文件中的位置。
void AVCtrl::set_seek_pos(int64_t _pos)
{
int64_t _pos_time = av_gettime() / MICROSECOND_TO_SECOND;
seek_flag = 1;
//加上 距离上次跳转到现在的时间差 作为最新的seek_pos, 并加上当前的变化量
seek_pos += (_pos + _pos_time - pos_time);
seek_pos = seek_pos < 0 ? 0 : seek_pos;
seek_pos = seek_pos > file_duration ? file_duration : seek_pos;
pos_time = _pos_time; //更新发生跳转时的时间
}
重定向文件使用av_seek_frame函数来实现,其函数定义如下:
int av_seek_frame(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags);
s:多媒体文件的句柄,即打开文件时所使用的AVFormatContext结构体;
stream_index:选择跳转后选取的数据流,如果为 -1,则选择默认流,并且时间戳会自动从 AV_TIME_BASE 单位转换为特定于流的 time_base;
timestamp:以 AVStream.time_base 为单位的时间戳,如果未指定流,则以 AV_TIME_BASE 为单位。
flags:用于选择方向和搜索模式的标志位(主要是对关键帧的选取),可选标志如下
/*跳转到非关键帧时, 往回找到关键帧, 作为跳转点*/
#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
返回≥0表示成功
因此在线程中检测重定事件是否发生,若发生了,则通过av_seek_frame函数进行文件重定向处理
if (avc->get_seek_flag()) {
avc->set_seek_flag(0);
av_seek_frame(avc->pFormatCtx, -1,
avc->get_seek_pos() * AV_TIME_BASE,
AVSEEK_FLAG_BACKWARD); //重定位文件, 定位至关键帧
........
}
当发生文件跳转时,原本demux时存取在队列中的数据包,以及解码后的数据包都不能使用,因此要进行清空队列操作。
