音视频解码流程详解

软解码基础流程

  1. 打开输入文件
  2. 读取媒体文件信息
  3. 查询视频流
  4. 获取解码器
  5. 获取解码器上下文
  6. 使用视频流的codecpar为解码器上下文赋值
  7. 打开解码器
  8. 获取原始数据帧
  9. 将数据发送给解码器
  10. 从解码器读取解码后的数据
  11. 获取图像转换上下文
  12. 将解码的图像格式转换成QImage

硬解码流程

基础步骤

  1. 打开输入文件
    • avformat_open_input
  2. 读取媒体文件信息
    • avformat_find_stream_info
  3. 查询视频流
    • av_find_best_stream
  4. 获取解码器
    • avcodec_find_decoder
  5. 获取解码器上下文
    • avcodec_alloc_context3
  6. 使用视频流的codecpar赋值
    • avcodec_parameters_to_context

硬件加速相关步骤

  1. 检索编解码器支持的硬件配置
    • avcodec_get_hw_config
  2. 遍历支持的编解码器设备类型
    • av_hwdevice_iterate_types
    • 在构造函数中记录支持的类型到数组
  3. 打开指定类型的编解码器设备
    • av_hwdevice_ctx_create
  4. 注册硬件像素格式回调
    • m_codecContext->get_format = get_hw_format

解码步骤

  1. 打开解码器
    • avcodec_open2
  2. 读取原始数据帧
    • av_read_frame
  3. 发送数据到解码器
    • avcodec_send_packet
  4. 读取解码后的数据
    • avcodec_receive_frame
  5. GPU数据拷贝到CPU
    • av_hwframe_transfer_data
    • av_hwframe_map(m_frameHW, m_frame, 0)
  6. 获取图像转换上下文
    • sws_getCachedContext
  7. 转换为QImage格式
    • sws_scale

软解码显示实现(PlayImage类)

基于QWidget

  1. 接收图像信号并响应updateImage槽函数
  2. 转换为QPixmap
  3. 调用update触发重绘
  4. paintEvent中绘制

YUV转RGB

  • FFmpeg默认解码为YUV格式
  • 使用sws_getCachedContext转换为RGB(AV_PIX_FMT_RGBA)

OpenGL渲染优化

软解码+OpenGL(YUV->RGB)

  1. 继承QOpenGLWidget和QOpenGLFunctions
  2. initializeGL中设置VAO/VBO/IBO
  3. updateImage中处理纹理
  4. paintGL中执行绘制

软解码+OpenGL(直接YUV)

  1. 使用AVFrame直接传递
  2. 使用三个纹理处理YUV数据
  3. 在GPU中完成格式转换

硬解码+OpenGL(NV12)

  1. 使用av_hwframe_map替代transfer_data
  2. 根据格式选择初始化方式
  3. 直接在GPU中完成NV12到RGB的转换

摄像头采集

  1. 注册设备
    • avdevice_register_all
  2. 查询输入设备
    • av_find_input_format
  3. 执行标准解码流程
  4. OpenGL中完成YUV转RGB

视频录制流程

  1. 创建输出上下文
    • avformat_alloc_output_context2
  2. 初始化IO上下文
    • avio_open
  3. 配置编码器
  4. 创建视频流
  5. 写入头信息
  6. 编码循环
  7. 写入尾信息