ffplay播放器 暂停、逐帧、音量、快进快退seek功能分析

理论知识

ffplay常⽤的播放器操作按键:

•播放:程序启动即播放,处于暂停时通过p或空格键

•静⾳:m键

•⾳量+:0键

•⾳量-:9键

•暂停:p或空格键

•快退/快进:左箭头/右箭头 10s pgup/pgon 60s

•逐帧:s键

•退出:q或Esc键

•全屏:f或者⿏标左键双击

接下来我们对以上功能实现进行做出分析!

疑问

1.能一直接收按键命令,并做出对应输出,这是什么技术?

ffplay使用事件循环机制(epoll网络模型底层相似) 监听键盘输入不断取出事件,做出相应处理。

2.播放、暂停 是如何实现?

  1. 画⾯要停⽌
    1. 画⾯停留在最后⼀帧
  2. 声⾳要停⽌
    1. ⾳频回调接⼝请求数据帧时直接填0 即输出静音
  3. 读取数据是否要停⽌?
    1. ⾳视频包缓存队列满时进⼊休眠。
  4. 暂停->继续 :时钟的恢复 线程唤醒。

3. 逐帧、调⾳量、静⾳是如何实现?

  1. 逐帧
    1. 逐帧播放的本质是,播放⼀帧图像,然后暂停。
  2. 调⾳量
    1. ⾳量控制的本质:控制采样点的幅值
    2. 静⾳,将采样点数值置为0
    3. ⾳量+,提升采样点的幅值
    4. ⾳量-,降低采样点的幅值

 4.快进快退,seek是如何实现?

前置知识:

  1. 移动播放分按字节(MP4格式不支持,主要支持有流媒体格式,ts,flv mp3)
    1. 每秒字节数:bitrate/8  如果快进5s则 当前字节位置 + 5 * 比特率 / 8字节数
  2. 按时间移动 时间戳移动 
    1. avformat_seek_file  flag=AVSEEK_FLAG_ANY时,就是强时间移动。比如i帧是200ms 移动到202ms,不设置则跳到200ms i帧所在处 ,设置了则在202 ,i帧不合理那就会造成画面马赛克
  3. 注意:不同的容器(⽐如MP4和FLV)seek的机制是不⼀样的。有些容器seek的时间会快些,有些则相对 耗时。这个和容器的存储结构有关系。

具体操作: SDLK_LEFT:后退10秒

SDLK_RIGHT:前进10秒

SDLK_UP:前进60秒

SDLK_DOWN:后退60秒

SDL_MOUSEMOTION:⿏标右键按下,seek到指定的位置,

最终也是调⽤stream_seek()

快进、快退、seek在ffplay的实现是⼀样的。

  1. 快进和快退的本质是seek到某个点重新开始播放。
    1. 跳转到指定的数据位置avformat_seek_file
    2. 清空packet队列
    3. 清空frame队列(在ffplay⾥⾯是通过serial去控制)
    4. 插⼊flush_pkt以便冲刷解码器
    5. 切换时钟序列(ffplay)
    6. 清空解码器
api
用于在媒体文件中搜索和定位指定时间点的函数。在指定的时间范围内寻找
最接近目标时间戳的位置,并将解码器定位到该位置。

int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);

AVFormatContext *s: 要搜索的 AVFormatContext 上下文。
int stream_index: 要搜索的流的索引,如果设为 -1 表示搜索所有流。
int64_t min_ts: 允许搜索的最小时间戳。
int64_t ts: 目标时间戳。
int64_t max_ts: 允许搜索的最大时间戳。
int flags: 搜索标志位,可以是以下值的组合:
    AVSEEK_FLAG_BACKWARD: 优先向后搜索。
    AVSEEK_FLAG_BYTE: 以字节为单位搜索。
    AVSEEK_FLAG_ANY: 允许在任意关键帧上搜索。
    AVSEEK_FLAG_FRAME: 以帧为单位搜索。
返回值:
成功返回 0。
失败返回负错误码。

5.退出播放是如何实现?

•关闭流          •销毁队列资源         •销毁线程         •退出:do_exit()

源码阅读

有了前面理论指导,查看源码就方便很多了。

1.event_loop

//这里是摘抄代码,为了大家更好理解
static void event_loop(VideoState *cur_stream){
    SDL_Event event;
     for (;;) {
         refresh_loop_wait_event(cur_stream, &event);//注册输入设备监听事件,不断取出事件队列处理。
        switch (event.type) {
            case SDLK_PAGEUP: //up 60
                if (cur_stream->ic->nb_chapters <= 1) {
                    incr = 600.0;
                    goto do_seek;
                }
                seek_chapter(cur_stream, 1);
                break;
            case SDL_QUIT: //退出
            case 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值