音视频流媒体开发【三十六】FFmpeg+QT播放器5-其他功能

音视频流媒体开发-目录

5-stream_open和stream_close

进⼀步掌握:

  • ijkmp_prepare_async处理逻辑
  • ijkmp_stop处理逻辑

stream_open

stream_open主要⼯作内容:
  • 初始化SDL以允许⾳频输出;
  • 初始化帧Frame队列
  • 初始化包Packet队列
  • 初始化时钟Clock
  • 初始化⾳量
  • 创建解复⽤读取线程read_thread
  • 创建视频刷新线程video_refresh_thread

这⾥需要注意的是我们只是列举了主要的逻辑,还有其他逻辑在后续不断优化的时候添加。

stream_close

stream_close主要⼯作内容:
  • 请求关闭read_thread线程
  • 关闭解复⽤器
  • 关闭stream,⽐如调⽤stream_component_close,该函数实现的时候涉及到:
    • 关闭解码线程
    • 释放解码器资源
    • 关闭对应的⾳频、视频设备
  • 消耗包队列
  • 消耗帧队列
    释放其他资源

6-解复⽤、数据读取read_thread设计

read_thread线程

实现解复⽤

stream_component_open

打开对应的解码器并做初始化
创建和启动解码线程
初始化⾳频或视频输出设备

stream_component_close

关闭解码器线程
释放解码器资源
关闭⾳频或视频输出设备

7-解码线程Decoder封装

  • stream_component_open
    • decoder_init
    • decoder_start
  • stream_component_close
    • decoder_abort
    • decoder_destroy

int audio_thread(void* arg); // ffplayer

int video_thread(void* arg);// ffplayer

8-⾳频输出

我们采⽤SDL作为⾳频输出。


  • ⾳频设备初始化
  • ⾳频设备输出回调函数
  • 重采样
  • buffer管理

9-视频渲染输出

⽬前使⽤qt输出, ui模块需要传⼊qt输出画⾯的回调。

重点内容

  1. 创建视频刷新线程video_refresh_thread,然后调⽤输出画⾯的回调函数。
  2. 设置视频刷新回调函数 从MainWind-> IjkMediaPlayer -> FFPlayer
  3. av_read_frame的video packet发给video packet queue
  4. 在DisplayWind 渲染画⾯
  5. 在调⽤stream_component_close的时候记得关闭 视频刷新线程video_refresh_thread

10-基本的⾳视频同步

难点

  • ⾳视频同步采⽤以⾳频为基准的⽅式。
  • ⾳频维系时间轴 视频时间戳怎么去对⽐⾳频时钟?
  • NaN(Not a Number,⾮数)是计算机科学中数值数据类型的⼀类值,表示未定义或不可表示的值。常在浮点数运 算中使⽤。

步骤

  1. 时钟结构设计和API设计
// 这⾥讲的系统时钟 是通过av_gettime_relative()获取到的时钟,单位为微妙
typedef struct Clock {
    double pts;            // 时钟基础, 当前帧(待播放)显示时间戳,播放后,当前帧变成上⼀帧
    // 当前pts与当前系统时钟的差值, audio、video对于该值是独⽴的
    double pts_drift;      // clock base minus time at which we updated the clock
    // 当前时钟(如视频时钟)最后⼀次更新时间,也可称当前时钟时间
    double last_updated;   // 最后⼀次更新的系统时钟
} Clock;
  1. stream_open中初始化时钟init_clock(&vidclk); init_clock(&audclk);
  2. 设置audio的时钟,在audio_decode_frame设置audio_clock, 然后在sdl_audio_callback设置audio时钟set_clock(&is->audclk, is->audio_clock);
  3. video时间戳⽐对audio时钟,在video_refresh
// 对⽐audio的时间戳
double diff = vp->pts - get_master_clock();
std::cout << __FUNCTION__ << "vp->pts:" << vp->pts << " - af->pts:" <<
get_master_clock() << ", diff:" << diff << std::endl;
if(diff > 0) {
    *remaining_time = FFMIN(*remaining_time, diff);
    return;
}

练习

  • 实现控制⽂件的⼤⼩
  • 实现暂停功能
  • 实现seek功能

你可能感兴趣的:(音视频流媒体开发【三十六】FFmpeg+QT播放器5-其他功能)