ffmpeg源码学习-2、ffplay源码学习(qt环境搭建到代码解析)
ffmpeg的ffplay源码学习,源码迁移到qt上进行编译研究ffplay框架调用流程音视频同步技术音视频seek操作
很多细节还是没有研究透
1、源码ffplay.c迁移qt编译
首先尝试了再vs下是要msvc进行编译发现报错误
: “unistd.h”: No such file or directory
百度解决方案意思是再linux下开发的C程序都需要头文件unistd.h,但VC中没有个头文件,
所以用VC编译总是报错。但是根据网上的方法,自己定义,h文件发现汇报其他错误
参考链接:https://www.cnblogs.com/ManMonth/archive/2010/02/01/1661142.html [转]VC报错 ‘unistd.h’: No such file or directory
则改到qt中新建工程引入ffplay.c
效果图
注意点:
1)编译环境&参数传入
2)运行时所需要的动态库和文件需要放过去
2、源代码解析
2.1、函数流程分析
参考公众号:txb玩linux中相关文章
入口函数main
main
init_dynload;win32设置动态库当前路径警告
av_log_set_flags
parse_loglevel
avdevice_register_all
parse_options
SDL_Init
SDL_CreateWindow
SDL_CreateRenderer
stream_open
frame_queue_init;创建循环帧队列,视频音频字幕
packet_queue_init;创建循环包队列,视频音频字幕
SDL_CreateCond;
init_clock ;初始化时钟 视频音频字幕
SDL_CreateThread(read_thread)
event_loop
read_thread线程主要完成解封装,读取多媒体包数据放入包缓冲队列中,
read_thread
//解封装
avformat_alloc_context;创建上下文结构体
interrupt_callback.callback = decode_interrupt_cb;设置中断回调函数
avformat_open_input;打开文件
avformat_find_stream_info;探测媒体类型,
avformat_seek_file;需要指定起始位置
is_realtime;是否为实时流媒体
av_find_best_stream;将为流的编解码器找到默认的解码器,视频音频字幕
av_guess_sample_aspect_ratio
set_default_window_size
stream_component_open;相应解码器,并创建相应的解码线程;视频、音频解码器字幕
avcodec_alloc_context3;编解码器上下文结构体
avcodec_parameters_to_context;将码流中的编解码器信息拷贝到新分配的编解码器上下文结构体
avcodec_find_decoder;codec_id查找解码器
音频
audio_open
SDL_Init
SDL_getenv
wanted_spec.callback = sdl_audio_callback;
decoder_init
decoder_start
SDL_CreateThread(audio_thread)//创建音频解码线程
视频
decoder_init
decoder_start
SDL_CreateThread(video_thread)//创建视频解码线程
字幕
decoder_init
decoder_start
SDL_CreateThread(subtitle_thread)
//读取多媒体包数据放入对应的包缓冲队列中
for (;;)
是否有seek请求
缓存队列有足够的包,不需要继续读取数据
av_read_frame;读取媒体数据、对应视频音频字幕
packet_queue_put;音视频数据分别送入相应的queue、对应视频音频字幕
event_loop 线程主要完成视频sdl显示及sdl的一些事件处理
//视频输出
event_loop
for (;;)
refresh_loop_wait_event
while (!SDL_PeepEvents)
av_usleep;remaining_time就是用来进行音视频同步的。
video_refresh;显示每一帧
frame_queue_peek
video_display
video_open;设置宽高,sdlwindows设置
SDL_SetRenderDrawColor
SDL_RenderClear
video_audio_display;播放声音
video_image_display;渲染视频
SDL_RenderPresent
sdl事件监听
sdl_audio_callback线程,主要完成声音的输出
//声音输出
sdl_audio_callback
while
audio_decode_frame
frame_queue_next
音频相关操作
update_sample_display
memcpy(stream, (uint8_t *)is->audio_buf
audio_thread线程主要完成从音频包缓冲队列中拿包解码将解码后的帧数据放入帧缓冲队列中
//音频解码
audio_thread
while
decoder_decode_frame
for (;;)
avcodec_receive_frame;从解码器中收到解码出的帧
while
packet_queue_get;从包缓冲队列中获取包
avcodec_send_packet;发生包到解码器中
frame_queue_push;将解码出来的帧放到帧队列中
video_thread线程主要是从视频包缓冲队列中拿包解码将解码后的帧数据放入帧缓冲队列中
//视频解码
video_thread
for (;;)
get_video_frame;获取解码后的视频帧
decoder_decode_frame
for (;;)
avcodec_receive_frame;从解码器中收到解码出的帧
while
packet_queue_get;从包缓冲队列中获取包
avcodec_send_packet;发生包到解码器中
queue_picture;将解码后的视频帧插入队列
frame_queue_peek_writable;检测队列是否有空间
set_default_window_size
frame_queue_push
2.2、如何做到音视频同步的
理论:在ffplay中 音视频同步有三种方式
以视频为基准,同步音频到视频
音频慢了就加快音频的播放速度,或者直接丢掉一部分音频帧
音频快了就放慢音频的播放速度
以音频为基准,同步视频到音频
视频慢了则加快播放或丢掉部分视频帧
视频快了则延迟播放
以外部时钟为准,同步音频和视频到外部时钟
根据外部时钟改版音频和视频的播放速度
2.2.1、以视频为基准,同步音频到视频
视频同步到音频是ffplay的默认同步方式。在视频播放线程中实现。视频播放函数video_refresh()实现了视频显示(包含同步控制)。
视频同步到音频的基本方法是:如果视频超前音频,则不进行播放,以等待音频;如果视频落后音频,则丢弃当前帧直接播放下一帧,以追赶音频。
2.2.2、音频同步到视频
音频同步到视频的方式,在音频播放线程中,实现代码在audio_decode_frame()及synchronize_audio()中。
2.2.3、以外部标准时钟为标准
具体细节之后研究
在之前双录写文件都是以标准时钟进行写入的
参考博客:
https://www.cnblogs.com/leisure_chn/p/10307089.html
3、seek步骤
参考:https://www.cnblogs.com/leisure_chn/p/10316225.html
参考博客:
https://www.cnblogs.com/leisure_chn/p/10301831.html
更多推荐
所有评论(0)