Skip to main content

ffplay 源码学习

version n8.2-dev-1241-g444f2cf047

Demuxing

main
└── stream_open
└── read_thread
├── avformat_alloc_context
├── avformat_open_input // 获取 input context
├── avformat_find_stream_info // 获取流信息
├── av_read_frame // 关键读取 packet 函数
├── packet_queue_put(&is->audioq, pkt)
├── packet_queue_put(&is->videoq, pkt) // pkt->stream_index == is->audio_stream
├── packet_queue_put(&is->subtitleq, pkt)
│ └── packet_queue_put_private
│ └── av_fifo_write // 将 packet 写入到环形队列中
└── avformat_close_input

解码

read_thread
└── stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO])
├── avcodec_alloc_context3(NULL)
├── avcodec_parameters_to_context
├── avcodec_find_decoder // 查找解码器
├── avcodec_open2 // 打开编码器
├── decoder_init // 初始化解码器
└── decoder_start(&is->viddec, video_thread, "video_decoder", is) // 启动解码线程
video_thread
└── get_video_frame
├── decoder_decode_frame
│ └── avcodec_receive_frame // 从解码器中读取一帧
└── queue_picture
└── frame_queue_push

Display

event_loop
└── refresh_loop_wait_event
└── video_refresh
└── video_display

音视频同步

ffplay 通过PTS (Presentation Time Stamp, 显示时间戳)主时钟 (Master Clock)实现音视频同步。ffplay 默认以音频为主时钟(-sync audio)。在于人类对声音的连续性和音调变化极其敏感,而对视频偶尔掉一帧或重复一帧(卡顿)的容忍度要高得多。

主时钟是用来同步音频和视频的“标准时间”。

1.音频时钟同步

audio_decode_frame

audclk 反映的是“当前播放位置”,而不是“已经解码到的位置”

get_clock
return c->pts_drift + time - (time - c->last_updated) * (1.0 - c->speed)

视频帧从解码器中取出后,会把 ptsduration 放入 Frame

queue_picture
vp->pts = pts;
vp->duration = duration;