• 音视频播放器—快进快退及逐帧播放


    ------------------------------------全系列文章目录------------------------------------

    快进快退

    大致流程

    在这里插入图片描述

    获取跳转的文件位置
    • 通过捕获SDL_KEYDOWN按键按下事件,并通过标志位判断当前的键位SDL_Event::SDL_KeyboardEvent::SDL_Keysym::SDL_KeycodeSDLK_LEFTSDLK_RIGHT,以此来确定是向前跳转还是向后跳转。

      switch (_event.type) {
          case SDL_KEYDOWN:
              switch (_event.key.keysym.sym) {
                  case SDLK_LEFT:
                      avc->set_seek_pos(-SEEK_POS_CHANGE);
                      break;
                  case SDLK_RIGHT:
                      avc->set_seek_pos(SEEK_POS_CHANGE);
                      break;
                  default:
                      break;
              }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
    • 使用一个标志位seek_pos来表示跳转到文件中的位置;每次发生跳转时,先更新当前文件位置,将seek_pos加上上次跳转时时间和当前时间的时间差作为最新的seek_pos;然后加上当前的跳转变化量,作为跳转到文件中的位置。

      void AVCtrl::set_seek_pos(int64_t _pos)
      {
          int64_t   _pos_time = av_gettime() / MICROSECOND_TO_SECOND;    
          seek_flag =  1;
          //加上 距离上次跳转到现在的时间差 作为最新的seek_pos, 并加上当前的变化量
          seek_pos  += (_pos + _pos_time - pos_time);
          seek_pos  =  seek_pos < 0 ? 0 : seek_pos;
          seek_pos  =  seek_pos > file_duration ? file_duration : seek_pos;
          pos_time  =  _pos_time;                    //更新发生跳转时的时间
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    重定向文件
    • 重定向文件使用av_seek_frame函数来实现,其函数定义如下:

      int av_seek_frame(AVFormatContext *s, int stream_index, 
                         int64_t timestamp, int flags);
      
      • 1
      • 2
      • s:多媒体文件的句柄,即打开文件时所使用的AVFormatContext结构体;

      • stream_index:选择跳转后选取的数据流,如果为 -1,则选择默认流,并且时间戳会自动从 AV_TIME_BASE 单位转换为特定于流的 time_base;

      • timestamp:以 AVStream.time_base 为单位的时间戳,如果未指定流,则以 AV_TIME_BASE 为单位。

      • flags:用于选择方向和搜索模式的标志位(主要是对关键帧的选取),可选标志如下

        /*跳转到非关键帧时, 往回找到关键帧, 作为跳转点*/
        #define AVSEEK_FLAG_BACKWARD 1 ///< seek backward   
        #define AVSEEK_FLAG_BYTE     2 ///< seeking based on position in bytes
        /*可以跳转到任何帧*/
        #define AVSEEK_FLAG_ANY      4 ///< seek to any frame, even non-keyframes
        /*跳转到非关键帧时, 往后找到关键帧, 作为跳转点*/
        #define AVSEEK_FLAG_FRAME    8 ///< seeking based on frame number
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
      • 返回≥0表示成功

    • 因此在线程中检测重定事件是否发生,若发生了,则通过av_seek_frame函数进行文件重定向处理

      if (avc->get_seek_flag()) {
          avc->set_seek_flag(0);
          av_seek_frame(avc->pFormatCtx, -1, 
                          avc->get_seek_pos() * AV_TIME_BASE, 
                          AVSEEK_FLAG_BACKWARD);    //重定位文件, 定位至关键帧
          ........
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • 当发生文件跳转时,原本demux时存取在队列中的数据包,以及解码后的数据包都不能使用,因此要进行清空队列操作。

    逐帧播放

    事件捕获
    • 通过捕获SDL_KEYDOWN按键按下事件,并通过标志位判断当前的键位SDL_Event::SDL_KeyboardEvent::SDL_Keysym::SDL_Keycode是否为一特定按键如SDLK_p来启动逐帧播放操作。需要注意的是SDLK_p按键应该在暂停时才会触发,并且需要保证播放完一帧后才会继续触发。
    大致流程如下
    • 当播放暂停时,若按下SDLK_p键,标记该事件,同时暂停接收SDLK_p按键事件;
    • 视频线程解码一帧,并将其显示出来;并判断当前视频帧pts是否大于音频帧pts,若大于则解锁音频播放标志;最后取消SDLK_p按键事件,并解锁再次接收SDLK_p按键事件;
    • 音频线程若检测到可以播放,则解码音频帧并播放,直到音频帧pts大于等于视频帧pts,则取消音频播放事件;
      在这里插入图片描述
  • 相关阅读:
    LeetCode-496-下一个更大元素
    Sora引发安全新挑战
    四、机器学习基础
    【计算思维】少儿编程蓝桥杯青少组计算思维题考试真题及解析B
    【开源分享】基于Html开发的房贷计算器,模仿新浪财经
    chatGPT底层原理是什么,为什么chatGPT效果这么好?三万字长文深度剖析-中
    windows bat 批处理常用命令
    【环境配置】使用Docker搭建LAMP环境
    存储器扩展,画图题
    PowerPC平台移植RTL8822BU
  • 原文地址:https://blog.csdn.net/weixin_44322983/article/details/125903123