欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

ffplay.c学习-8-暂停、逐帧、⾳量

发布时间:2024/4/11 编程问答 51 豆豆
生活随笔 收集整理的这篇文章主要介绍了 ffplay.c学习-8-暂停、逐帧、⾳量 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

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()实现状态翻转:
  • /* pause or resume the video */ static void stream_toggle_pause(VideoState *is) {// 如果当前是暂停 -> 恢复播放// 正常播放 -> 暂停if (is->paused) {// 当前是暂停,那这个时候进来这个函数就是要恢复播放/* 恢复暂停状态时也需要恢复时钟,需要更新vidclk */// 加上 暂停->恢复 经过的时间is->frame_timer += av_gettime_relative() / 1000000.0 - is->vidclk.last_updated;if (is->read_pause_return != AVERROR(ENOSYS)) {is->vidclk.paused = 0;}// 设置时钟的意义,暂停状态下读取的是单纯pts// 重新矫正video时钟set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial);}set_clock(&is->extclk, get_clock(&is->extclk), is->extclk.serial);// 切换 pause/resume 两种状态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()函数中有如下代码:
  • /* called to display each frame */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; // 暂停返回-1, 但这⾥返回-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 the stream is paused unpause it, then step */if (is->paused)stream_toggle_pause(is); // 确保切换到播放状态,播放⼀帧画⾯is->step = 1;} /* called to display each frame */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的⽅式供参考
  • //根据audio_volume决定如何输出audio_buf/* 判断是否为静音,以及当前音量的大小,如果音量为最大则直接拷贝数据 */// 最大音量则直接拷贝解码后的原始数据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 {// 先将数据清零,如果不再拷贝新数据给stream,则输出静音memset(stream, 0, len1);// 3.调整音量// 不为静音则通过SDL_MixAudioFormat来调整解码后数据的幅值来实现音量的变化/* 如果处于mute状态则直接使用stream填0数据, 暂停时is->audio_buf = NULL */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//根据audio_volume决定如何输出audio_buf/* 判断是否为静音,以及当前音量的大小,如果音量为最大则直接拷贝数据 */// 最大音量则直接拷贝解码后的原始数据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 {// 先将数据清零,如果不再拷贝新数据给stream,则输出静音memset(stream, 0, len1);// 3.调整音量// 不为静音则通过SDL_MixAudioFormat来调整解码后数据的幅值来实现音量的变化/* 如果处于mute状态则直接使用stream填0数据, 暂停时is->audio_buf = NULL */if (!is->muted && is->audio_buf)SDL_MixAudioFormat(stream, (uint8_t *) is->audio_buf + is->audio_buf_index,AUDIO_S16SYS, len1, is->audio_volume);}

    总结

    以上是生活随笔为你收集整理的ffplay.c学习-8-暂停、逐帧、⾳量的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。