1:原理
ffmpeg读取出来一个包如果是视频包放入视频包队列,如果是音频包放入音频包队列。
视频:从视频队列中取出一个包解码根绝帧率或pts等等算出一帧数据的持续时间将这一帧数据放入VideoPicture这个结构体的bmp中,这只是内存,还未到显示,根据,Sleep()控制时间显示这一帧视频,并算出下一次刷新的时间,此时消耗了一个VideoPicture这个结构体的bmp。重新循环。
音频:从音频队列中取出一个包解码,SDL_AudioSpec这个结构体SDL已经算出了一帧音频的持续时间,所以音频将解码后的数据放入SDL缓存的末尾,并传给声卡,声卡消耗数据的大小和时间是前面能算出来的,所以一直在播放。
2:程序初始化InitProgram()
程序启动做的初始化 打开编解码库 SDL初始化等,音视频全局结构体StreamState初始化,获取全屏的屏幕宽高,设置SDL事件状态。全局结构体StreamState只初始化一次,以及成员变量的清零等。
3:程序释放UinitProgram()
音视频全局结构体StreamState释放。关闭编解码库 ,sdl库释放,以及成员变量的清零等。
4:变量的初始化InitVariable()
这里除了需要将变量设成默认值之外 还要做
//创建全局条件变量互斥变量
m_streamstate->pictq_mutex = SDL_CreateMutex();
m_streamstate->pictq_cond = SDL_CreateCond();
//刷新packet初始化
av_init_packet(&m_flush_pkt);
m_flush_pkt.data = (uint8_t *)(intptr_t)"FLUSH";
5:变量的释放UinitVariable()
要将成员变量的值最处理清零或设成默认值,还有一些工作
还要将音视频的解码线程关掉
6:获取程序初始化的时候控件的位置Access_control_position()
这个的作用是当改变窗口大小的时候需要将控件的大小以及位置做调整
8:文件打开获取信息OnBnClickedButtonLoad()
extern int m_video_stream_idx; //视频在文件中的流标号
extern double m_dbFrameRate; //视频帧率
extern double m_video_duration; //视频单帧持续时间 秒(s)
extern int m_dwWidth; //宽
extern int m_dwHeight; //高
extern AVCodecID m_video_codecID; //视频编码类型
extern AVPixelFormat m_video_pixelfromat; //视频yuv类型
extern char m_spspps[100]; //spspps_buf
extern int m_spspps_size; //spspps_size
//audio pram
extern int m_audio_stream_idx; //音频在文件中的流标号
extern double m_audio_duration; //音频单帧持续时间 秒(s)
extern int m_dwChannelCount; //声道
extern int m_dwBitsPerSample; //样本
extern int m_dwFrequency; //采样率
extern AVCodecID m_audio_codecID; //视频编码类型
extern int m_audio_frame_size; //一帧数据大小
还要判断要打开的文件的类型
将音视频信息添加到list控件上
9:打开操作创建线程OnBnClickedButtonOpen()
这里要创建3个线程一个回调函数
10:暂停操作OnBnClickedButtonPlayPause()
这里既不像窗口画视频,不解码音频数据,暂停播放设备,让线程空跑,再点击还原。
11:停止操作OnBnClickedButtonStop()
将stop标志设置为 1,音视频编解码,以及读取,刷新线程相继退出。
12:退出OnBnClickedCancel()
13:全屏操作OnLButtonDblClk()
14:进度条控制OnHScroll()
然后在read_thread中调用
15:静音操作OnBnClickedCheckMute()
在audio_callback 中控制音量大小
16:读取线程read_thread()
创建刷新线程,创建创建音频回调函数,视频线程。循环像队列里面读取分别读取音视频包,如果遇到seek操作则调用seek函数,
如果遇到stop则关闭视频 关闭音频设备。
17:音频回调函数audio_callback()
取出一包帧数据解码之后传给声卡(传给声卡是SDL做的)。
18:视频线程video_thread()
和音频道理一样,只是将解码后的yuv数据传到窗口 可能需要改变大小。
19:刷新线程refresh_thread()
这个就是计算是什么时候显示一帧视频数据的。
20:效果
其它的东西有些是mfc的操作有些都是ffplay的东西可以借鉴,我的ffmpeg版本不太清楚了记得是12年11月份的,sdl版本是SDL-1.2.15。
程序还有很多功能完善,优化的地方,暂时写第一个版本。有时间再完善。
源码地址:
win32版本:http://download.csdn.net/detail/zhuweigangzwg/6000463
MFC版本: http://download.csdn.net/detail/zhuweigangzwg/6000505
希望交流的可以加我QQ379969650.