《ffplay的数据结构分析》
《ffplay分析(从启动到读取线程的操作)》
《ffplay分析(视频解码线程的操作)》
《ffplay分析(音频解码线程的操作)》
《ffplay 分析(音频从Frame(解码后)队列取数据到SDL输出)》
《ffplay分析 (音视频同步:主时钟为音频)》
《ffplay分析 (暂停 / 播放处理)》
《ffplay分析 (seek操作处理)》
《ffplay源码(版本:ffmpeg-4.2.1)》
ffplay分析 (视频从解码后队列取数据到SDL输出)
- 一、分析:
- 1、main():在main()函数开始时有创建SDL窗口的处理
- 2、read_thread():开启读取线程后,在read_thread()读取数据线程中设置视频流时调用set_default_window_size()设置显示窗口的默认大小和渲染区域大小
- 3、set_default_window_size():判断命令行是否有指定宽高没有就使用帧宽高,作为窗口宽高调用calculate_display_rect()计算渲染区域
- 4、calculate_display_rect():使用像素比例计算实际宽高比
- 5、calculate_display_rect():首先使用高度为基准计算渲染区域,如果宽度大于实际窗口再以宽度为基准重新计算
- 6、calculate_display_rect():计算保存返回上层的渲染区域参数
- 7、event_loop():SDL的事件循环调用了refresh_loop_wait_event()进行更新显示和获取SDL事件(在主线程更新,event_loop()在主线程调用)
- 8、refresh_loop_wait_event():调用SDL_PumpEvents()、SDL_PeepEvents()、获取SDL事件。如果没有事件才进入while更新画面,否则返回上一层处理相应事件。
- 9、refresh_loop_wait_event():调用usleep()等待同步和设置remaining_time默认等待时间
- 10、refresh_loop_wait_event():调用video_refresh()进行视频更新
- 11、video_refresh():判断是否是实时流操作
- 12、video_refresh():判断是否是音频流显示操作
- 13、video_refresh():视频流显示操作,如果没有数据就什么不做
- 14、video_refresh():获取上一帧显示的帧和将要显示的一帧,用来计算同步时间操作
- 15、video_refresh():判断将要显示的一帧的序列与现在解码的不同就直接抛弃,重新获取
- 16、video_refresh():判断是否是新的播放序列,重置is->frame_timer
- 17、video_refresh():判断是否暂停,直接保持显示
- 18、video_refresh():计算上一帧持续显示的时长
- 19、video_refresh():根据计算得到的delay判断是否继续显示上一帧还是往下走继续更新
- 20、video_refresh():根据is->frame_timer用于下一轮的操作
- 21、video_refresh():更新当前的视频时钟
- 22、video_refresh():判断是否进行丢帧处理
- 23、video_refresh():调用frame_queue_next()移动到下一帧
- 24、video_refresh():调用video_display()真正开始渲染画面的操作
- 25、video_display():判断是视频流调用video_image_display()显示
- 26、video_image_display():获取将要显示的这一帧![在这里插入图片描述](https://img-blog.csdnimg.cn/20210128164947276.png)
- 27、video_image_display():调用calculate_display_rect()根据窗口比例计算渲染区域(图像)的宽高,调用upload_texture()将frame的yuv更新到is->vid_texture(SDL_Texture)
- 28、video_display():video_image_display()结束后,返回到video_display()最终调用SDL_RenderPresent()显示画面