我们要进行音视频文件的seek操作,又是怎么做的呢?
通过下面的流程图我们可以清晰的看到怎样进行的操作
我们对
ffp_seek_to_l进行分析
int ffp_seek_to_l(FFPlayer *ffp, long msec)
{
assert(ffp);
VideoState *is = ffp->is;
int64_t start_time = 0;
//转换成要跳转的时间基和总时长的事件基 msec /1000 * AV_TIME_BASE AV_TIME_BASE代表1秒
int64_t seek_pos = milliseconds_to_fftime(msec);
int64_t duration = milliseconds_to_fftime(ffp_get_duration_l(ffp));
if (!is)
return EIJK_NULL_IS_PTR;
//跳转的位置大于duration,暂停
if (duration > 0 && seek_pos >= duration && ffp->enable_accurate_seek) {
toggle_pause(ffp, 1);
ffp_notify_msg1(ffp, FFP_MSG_COMPLETED);
return 0;
}
//第一帧开始的事件,用AV_TIME_BASE作为单位
start_time = is->ic->start_time;
//跳转位置目前我们知道seek_pos是与第一帧的时间的偏移量,我们要计算一个绝对值
if (start_time > 0 && start_time != AV_NOPTS_VALUE)
seek_pos += start_time;
// FIXME: 9 seek by bytes
// FIXME: 9 seek out of range
// FIXME: 9 seekable
av_log(ffp, AV_LOG_DEBUG, "stream_seek %"PRId64"(%d) + %"PRId64", \n", seek_pos, (int)msec, start_time);
stream_seek(is, seek_pos, 0, 0);
return 0;
}
这个函数就是将跳转的时间,换成相对于第一帧图像的以时间基为单位的绝对值。‘
static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes)
{
if (!is->seek_req) {
is->seek_pos = pos;
is->seek_rel = rel;
is->seek_flags &= ~AVSEEK_FLAG_BYTE;
if (seek_by_bytes)
is->seek_flags |= AVSEEK_FLAG_BYTE;
is->seek_req = 1;
SDL_CondSignal(is->continue_read_thread);
}
}
这个函数就是对seek相关的变量赋值
下面的函数式实际的seek操作函数
static int read_thread(void *arg)
{
.....
for (;;) {
......
if (is->seek_req) {
int64_t seek_target = is->seek_pos;
int64_t seek_min = is->seek_rel > 0 ? seek_target - is->seek_rel + 2: INT64_MIN;
int64_t seek_max = is->seek_rel < 0 ? seek_target - is->seek_rel - 2: INT64_MAX;
// FIXME the +-2 is due to rounding being not done in the correct direction in generation
// of the seek_pos/seek_rel variables
ffp_toggle_buffering(ffp, 1);
ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_UPDATE, 0, 0);
av_log(NULL, AV_LOG_ERROR, "yuanxuzhen is->seek_flags=%d", is->seek_flags);
ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR,
"%s: error while seeking\n", is->ic->filename);
} else {
if (is->audio_stream >= 0) {
packet_queue_flush(&is->audioq);
packet_queue_put(&is->audioq, &flush_pkt);
// TODO: clear invaild audio data
// SDL_AoutFlushAudio(ffp->aout);
}
if (is->subtitle_stream >= 0) {
packet_queue_flush(&is->subtitleq);
packet_queue_put(&is->subtitleq, &flush_pkt);
}
if (is->video_stream >= 0) {
if (ffp->node_vdec) {
ffpipenode_flush(ffp->node_vdec);
}
packet_queue_flush(&is->videoq);
packet_queue_put(&is->videoq, &flush_pkt);
}
if (is->seek_flags & AVSEEK_FLAG_BYTE) {
set_clock(&is->extclk, NAN, 0);
} else {
set_clock(&is->extclk, seek_target / (double)AV_TIME_BASE, 0);
}
is->latest_video_seek_load_serial = is->videoq.serial;
is->latest_audio_seek_load_serial = is->audioq.serial;
is->latest_seek_load_start_at = av_gettime();
}
ffp->dcc.current_high_water_mark_in_ms = ffp->dcc.first_high_water_mark_in_ms;
is->seek_req = 0;
is->queue_attachments_req = 1;
is->eof = 0;
#ifdef FFP_MERGE
if (is->paused)
step_to_next_frame(is);
#endif
completed = 0;
SDL_LockMutex(ffp->is->play_mutex);
if (ffp->auto_resume) {
is->pause_req = 0;
if (ffp->packet_buffering)
is->buffering_on = 1;
ffp->auto_resume = 0;
stream_update_pause_l(ffp);
}
if (is->pause_req)
step_to_next_frame_l(ffp);
SDL_UnlockMutex(ffp->is->play_mutex);
if (ffp->enable_accurate_seek) {
is->drop_aframe_count = 0;
is->drop_vframe_count = 0;
SDL_LockMutex(is->accurate_seek_mutex);
if (is->video_stream >= 0) {
is->video_accurate_seek_req = 1;
}
if (is->audio_stream >= 0) {
is->audio_accurate_seek_req = 1;
}
SDL_CondSignal(is->audio_accurate_seek_cond);
SDL_CondSignal(is->video_accurate_seek_cond);
SDL_UnlockMutex(is->accurate_seek_mutex);
}
ffp_notify_msg3(ffp, FFP_MSG_SEEK_COMPLETE, (int)fftime_to_milliseconds(seek_target), ret);
ffp_toggle_buffering(ffp, 1);
}
......
}
.....
}
我们可以看到avformat_seek_file这样就对音视频进行了seek