FFplay播放文件暂停代码分析
这里主要对ffplay在播放暂停时的代码实现过程,在此主要是说明播放本地视频文件。
1.暂停主要分为视频暂停和音频暂停,是通过响应键盘p/Space 2个按键的。
case SDLK_p:
case SDLK_SPACE:
toggle_pause(cur_stream);
break;
toggle_pause
的代码实现如下:
static void toggle_pause(VideoState *is)
{
stream_toggle_pause(is);
is->step = 0;
}
stream_toggle_pause
的主要关键代码如下,对视频、音频、外部都进行取反赋值,实现暂停/播放来回切换:
/* pause or resume the video */
is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused = !is->paused;
2.视频部分暂停代码实现
进入/* called to display each frame */
static void video_refresh(void *opaque, double *remaining_time)
函数中,这是调用显示视频每一帧的
if (is->paused)
goto display;
这个goto跳转到:display实现暂停功能,它直接显示当前显示的帧,跳过了frame_queue_next(&is->subpq);函数。就是播放的帧没有变化,不移动(删除),实现暂停功能。
3.音频部分暂停代码
进入SDL的音频回调函数中static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
,找到如下代码:
audio_size = audio_decode_frame(is);
if (audio_size < 0) {
/* if error, just output silence */
is->audio_buf = NULL;
is->audio_buf_size = SDL_AUDIO_MIN_BUFFER_SIZE / is->audio_tgt.frame_size * is->audio_tgt.frame_size;
continue; **//这一行是后来增加的**
}
进入audio_decode_frame(is);
的代码中发现暂停的操作了,如下:
av_unused double audio_clock0;
int wanted_nb_samples;
Frame *af;
if (is->paused)
return -1;
当暂停的时候audio_size的值是-1,所以在播放本地文件时,此处不能再执行后面的代码了,否则音频时无法暂停的,此处用continue可以实现暂停播放文件,实测时可行的。
如果不用continue代码跳转,sdl_audio_callback就会执行如下代码:
len -= len1;
stream += len1;
is->audio_buf_index += len1;
这里很明显是buffer中的数据读取位置在移动,是不能实现音频暂停的。
实际的打印log也是如此:
上述只是个人调试FFplay代码的情况,仅供参考交流。