FFplay播放完毕分析—ffplay.c源码分析

作者:罗上文,微信:Loken1,公众号:FFmpeg弦外之音

FFplay 播放器播放完一个 mp4 文件的时候,画面就会停止在最后一帧。如下:

1-1

本文主要介绍,当播放完毕的时候,各个解复用线程,解码线程,播放线程在干什么。


main主线程/视频播放线程,播放完毕之后,它在干什么?

播放完一个文件之后,main 主线程实际上是没有受到什么影响的,还是不断在 event_loop() 里面循环,检测键盘/窗口事件有没发生,大部分情况每隔 0.01s 调一次 video_refresh() 看看有没下一帧数据可以播放。

但是由于已经播放完毕,所以 FrameQueue 里面是空的,所以 video_refresh() 基本上相当于什么都没做。

1-2

虽然已经播放完毕,但是还是可以按 🠔 键 后退到某个时间点,后退之后, FrameQueue 就会又有数据,这样 video_refresh() 就会继续播放画面。


read_thread解复用线程,播放完毕之后,它在干什么?

1-3

read_thread 解复用线程 读到 AVERROR_EOF 的时候,就会往解码器丢 空的 AVPacket ,这样可以让解码器把所有缓存的帧都刷出来去播放。

is->eof 变量代表 mp4 文件是否已经播放完毕。

最后会调 SDL_CondWaitTimeout() 休眠 10ms,然后再继续跑,不断调 av_read_frame() 函数,看看能不能读到数据。

当后退,跳转时间点播放的时候,av_read_frame() 就能重新读到数据了。


video_thread视频解码线程,播放完毕之后,它在干什么?

由于 read_thread解复用线程 一直读不出来 AVPacket ,所以 PacketQueue 会一直没有数据能拿出来解码,PacketQueue 队列是空的。

PacketQueue 队列没有数据,就会导致 video_thread 线程一直阻塞packet_queue_get() 函数里面。函数调用流程如下:

1-4


audio_thread音频解码线程,播放完毕之后,它在干什么?

audio_thread 跟 video_thread 一样,音频流的 PacketQueue 队列也没有数据,所以也会一直阻塞packet_queue_get() 函数里面。

1-5


sdl_audio_callback音频播放线程分析,播放完毕之后,它在干什么?

因为文件播放完毕 ,导致 FrameQueue 队列空了,所以 sdl_audio_callback 会阻塞在 frame_queue_peek_readable() 函数里面,如下:

1-6

1-7


总结,当播放完一个 mp4 的时候,各个线程状态如下:

1,main主线程,没什么影响,还是正常地处理事件。

2,read_thread 解复用线程,会进行短暂的休眠(10ms)

3,video_thread 视频解码线程,会进行永久休眠,阻塞在 packet_queue_get() 函数里面。

4,audio_thread 音频解码线程,会进行永久休眠,阻塞在 packet_queue_get() 函数里面。

5,sdl_audio_callback 音频播放线程,会进行永久休眠,阻塞在 frame_queue_peek_readable() 函数里面。

上面这些永久休眠,都是可以通过 cond 条件变量来唤醒的。

分析完毕。



感谢 NETINT(镕铭微电子) 赞助《FFmpeg原理》免费版一书的服务器费用,下面是 VPU 产品介绍

版权所属 xianwanzhiyin.net 罗上文 2024 all right reserved,powered by Gitbook该文件修订时间: 2023-05-17 11:39:55

results matching ""

    No results matching ""