ffplay.c学习-8-暂停、逐帧、⾳量
目录
播放、暂停
暂停/继续状态切换 暂停状态下的视频播放 暂停状态下的⾳频播放 逐帧、调⾳量、静⾳
逐帧 调⾳量 静⾳
常⽤的播放器操作:
播放:程序启动即播放,处于暂停时通过p或空格键 静⾳:m键 ⾳量+:0键 ⾳量-:9键 暂停:p或空格键 快退/快进:左箭头/右箭头 逐帧:s键 退出:q或Esc键 全屏:f或者⿏标左键双击 event_loop做按键响应
1. 播放、暂停
画⾯要停⽌
画⾯停留在最后⼀帧 声⾳要停⽌
⾳频回调接⼝请求数据帧时直接填0 读取数据是否要停⽌?
⾳视频包缓存队列满时进⼊休眠。 暂停->继续 :时钟的恢复 暂停:toggle_pause()
1. 暂停/继续状态切换
函数调⽤关系如下
main ( ) -- >
event_loop ( ) -- >
toggle_pause ( ) -- >
stream_toggle_pause ( )
stream_toggle_pause()实现状态翻转:
static void stream_toggle_pause ( VideoState * is)
{
if ( is- > paused) {
is- > frame_timer += av_gettime_relative ( ) / 1000000.0 - is- > vidclk. last_updated;
if ( is- > read_pause_return != AVERROR ( ENOSYS) ) {
is- > vidclk. paused = 0 ;
}
set_clock ( & is- > vidclk, get_clock ( & is- > vidclk) , is- > vidclk. serial) ;
}
set_clock ( & is- > extclk, get_clock ( & is- > extclk) , is- > extclk. serial) ;
is- > paused = is- > audclk. paused = is- > vidclk. paused = is- > extclk. paused = ! is- > paused;
printf ( "is->step = %d; stream_toggle_pause\n" , is- > step) ;
}
2. 暂停状态下的视频播放
在video_refresh()函数中有如下代码:
static void video_refresh ( void * opaque, double * remaining_time)
{
... ...
if ( is- > video_st) {
... ...
if ( is- > paused)
goto display;
... ...
}
... ...
}
在暂停状态下,实际就是不停播放上⼀帧(最后⼀帧)图像。画⾯不更新.
3. 暂停状态下的⾳频播放
sdl_audio_callback -> audio_decode_frame
static int audio_decode_frame ( VideoState * is)
{
int data_size, resampled_data_size;
int64_t dec_channel_layout;
av_unused double audio_clock0;
int wanted_nb_samples;
Frame * af;
( is- > paused)
return - 1 ;
... .
}
2. 逐帧、调⾳量、静⾳
1. 逐帧
逐帧播放的本质是,播放⼀帧图像,然后暂停。 涉及到的函数和变量:
step_to_next_frame() is->step = 1时单步播放⼀帧,然后paused 逐帧播放流程
按s键,如果当前处于暂停则启动播放; 播放⼀帧数据然后进⼊暂停状态 逐帧播放是⽤户每按⼀次s键,播放器播放⼀帧画面。 逐帧播放实现的⽅法是:每次按了s键,就将状态切换为播放,播放⼀帧画⾯后,将状态切换为暂停。 函数调⽤关系如下:
main ( ) -- >
event_loop ( ) -- >
step_to_next_frame ( ) -- >
stream_toggle_pause ( )
实现代码⽐较简单,如下:
static void step_to_next_frame ( VideoState * is)
{
if ( is- > paused)
stream_toggle_pause ( is) ;
is- > step = 1 ;
}
static void video_refresh ( void * opaque, double * remaining_time) {
... ...
if ( is- > video_st) {
... ...
if ( is- > step && ! is- > paused)
stream_toggle_pause ( is) ;
... ...
}
... ...
}
2. 调⾳量
⾳量控制的本质:控制采样点的幅值
静⾳,将采样点数值置为0 ⾳量+,提升采样点的幅值 ⾳量-,降低采样点的幅值
1. ffplay控制⾳量的⽅式
最⼤⾳量:输出解码后的原始数据 静⾳:即是输出数值为0的数据
toggle_mute() 改变⾳量:通过SDL_MixAudioFormat改变解码后数据的幅值
update_volume() ⽐如下所示(sdl_audio_callback函数内): 以下是ffplay的⽅式供参考
if ( ! is- > muted && is- > audio_buf && is- > audio_volume == SDL_MIX_MAXVOLUME)
memcpy ( stream, ( uint8_t * ) is- > audio_buf + is- > audio_buf_index, len1) ;
else {
memset ( stream, 0 , len1) ;
if ( ! is- > muted && is- > audio_buf)
SDL_MixAudioFormat ( stream, ( uint8_t * ) is- > audio_buf + is- > audio_buf_index,
AUDIO_S16SYS, len1, is- > audio_volume) ;
}
3. 静⾳
static void toggle_mute ( VideoState * is)
{
is- > muted = ! is- > muted;
}
`` `go
if ( ! is- > muted && is- > audio_buf && is- > audio_volume == SDL_MIX_MAXVOLUME)
memcpy ( stream, ( uint8_t * ) is- > audio_buf + is- > audio_buf_index, len1) ;
else {
memset ( stream, 0 , len1) ;
if ( ! is- > muted && is- > audio_buf)
SDL_MixAudioFormat ( stream, ( uint8_t * ) is- > audio_buf + is- > audio_buf_index,
AUDIO_S16SYS, len1, is- > audio_volume) ;
}