前言
ffplay 是入门播放器的非常合适的一个开源项目,支持本地视频文件播放,也支持网络流的播放。通过对 ffplay 的学习可以知道一个播放器如何工作的。这篇文章先整体介绍一下 ffplay 播放器的整体架构。从整体上对播放器的设计有个大概的了解。ijkplayer播放器内核是基于ffplay开发的,所以掌握 ffplay 对于开发播放器是非常有帮助的。
ffplay 简介
ffplay 是 FFmpeg 工程自带的简单播放器,使用 FFmpeg 提供的解码器和SDL库进行视频播放。整个源码ffplay.c只有3k多行。麻雀虽小五脏俱全。在视频文件的播过中,一般要涉及到文件读取、解封装、视频解码、音频解码、视频渲染、音频播放、音视频同步等技术。
下面贴一张 ffplay的整体架构图
ffplay中的线程
ffplay 进程中一个有以下 5个线程。
主线程
ffplay 主线程负责键盘消息处理以及图像渲染,并且创建解复用线程 read_thread 。ffplay的渲染使用sdl库进行渲染。
ffplay -h 查看使用手册
ffplay支持的键盘消息
While playing:
q, ESC quit
f toggle full screen
p, SPC pause
m toggle mute
9, 0 decrease and increase volume respectively
/, * decrease and increase volume respectively
a cycle audio channel in the current program
v cycle video channel
t cycle subtitle channel in the current program
c cycle program
w cycle video filters or show modes
s activate frame-step mode
left/right seek backward/forward 10 seconds or to custom interval if -seek_interval is set
down/up seek backward/forward 1 minute
page down/page up seek backward/forward 10 minutes
right mouse click seek to percentage in file corresponding to fraction of width
left double-click toggle full screen
解复用线程 read_thread
读取本地文件或者网络媒体流,读取文件中的视频包和音频包,并放入视频队列和音频队列,供视频解码线程和音频解码线程解码使用。
在解复用线程中创建了音频播放线程,音频解码线程,视频解码线程,字幕解码线程。
视频解码线程 video_thread
从 video packets队列缓冲区读取视频包,解码后将视频帧放入 video frame队列,供渲染线程使用。
音频解码线程 audio_thread
从 audio packets缓冲区读取音频包,解码后将pcm格式的音频数据放入 audio frames队列,供音频播放线程播放使用。
音频播放线程
从audio frame队列获取解码后的音频包,如果需要进行格式转换后共给声卡播放。
ffplay使用SDL库播放音频,该线程实际上是SDL的内部线程。
总结
一个播放器的流程如下
- 打开视频文件或者网络流
- 解封装从文件或者网络流读取音频包视频包,并放入对应缓冲区
- 音频解码,视频解码,将解码后的视频帧,音频帧放入队列等待播放
- 音视频对齐后,进行画面的渲染,音频的播放
技术参考
1.本文部分技术点出处:FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发
2.ffplay源码分析3:https://www.cnblogs.com/leisure_chn/p/10301831.html