基于ffmpeg网络播放器的教程与总结

上传人:艾力 文档编号:36364928 上传时间:2018-03-28 格式:DOCX 页数:27 大小:43.85KB
返回 下载 相关 举报
基于ffmpeg网络播放器的教程与总结_第1页
第1页 / 共27页
基于ffmpeg网络播放器的教程与总结_第2页
第2页 / 共27页
基于ffmpeg网络播放器的教程与总结_第3页
第3页 / 共27页
基于ffmpeg网络播放器的教程与总结_第4页
第4页 / 共27页
基于ffmpeg网络播放器的教程与总结_第5页
第5页 / 共27页
点击查看更多>>
资源描述

《基于ffmpeg网络播放器的教程与总结》由会员分享,可在线阅读,更多相关《基于ffmpeg网络播放器的教程与总结(27页珍藏版)》请在金锄头文库上搜索。

1、基于 ffmpeg 网络播放器的教程与总结一、 概述为了解决在线无广告播放 youku 网上的视频。(youku 把每个视频切换成若干个小视频)。视频资源解析可以从网上获取,此网站根据你输入的优酷的播放网页地址解析成若干个真实的视频地址。二、 实现首先搜索关闭网络播放器(流媒体播放器的实现方法)得出的结论,目前主流的播放器分三大阵营微软,苹果,基于 FFmpeg 内核的。所以我决定从 ffmpeg 开源的播放器入手。最出名的 ffmpeg 播放器 vcl 播放器,开源免费。最后选择放弃。原因1 依赖于 vcl 的 68M 的 plugins 和 libvlccore.dll,libvlc.dl

2、l 项目生成文件过大。2 即使这样不能解决播放多段视频卡顿现象。最后决定使用 ffmpeg 官方的 ffpaly 播放器只有 1000 多行 (很激动),使用 ffmpeg 编解码,使用 sdl 做显示。本想只修改下就行了。结果发现里面代码结构过于复杂,搞懂每行很是吃力。而且是用 sdl 做显示,sdl 需要句柄。而我这个是为wpf 项目量身定做的。Wpf 只有顶层窗口有句柄。如果是使用 wpf 嵌入 winform 控件。导致此 winform 控件只能最上层显示(原因是 wpf 是 directui 思想实现的)。所以也放弃了。决定使用 ffmpeg 库,自己开发查看网上关于 ffmpeg

3、 开发的总结。对 ffmpeg 开发有个总体方向。首先我们先把视频搞出来,参考网上 100 行代码搞定视频。然后 100 行搞定音频网上 这样视频音频都已经搞出来了。但是我们怎么把视频音频一起搞出来呢?Csdn 有一份文档网上此文档介绍了用 ffmpeg 开发视频播放器的详细方法,有注解。但是已经过时了。最新的代码在网上但是文档中的思想还是挺受用的。代码不同,思想是通的。结论,视频包含视频流,音频流,字幕流(一般没有),音视频同步跟进播放时间戳 pts 来做的。 视频和音频得出 pts 的方式有所不同。具体看文档。如果按文档的注释,然后根据 github 的代码,编译我们发现视频可以显示,音频

4、出现乌拉乌拉的杂音。 此时我参考 100行搞定音频网上源码修改了 github 的音频部分。调试运行,可以播放了。至此 我们的视频播放器可以播放了 ,使用 sdl 做显示。那现在我们还是没解决问题。网络播放器,多段无卡顿。在此基础上我们分析,可以开辟一个线程从网络上下载视频,音频,放入到缓冲队列。音视频播放线程从缓冲区读取数据解析。这就是网络播放器的原理,而且不会卡顿。其中音视频同步用音频驱动视频的方式实现。显示目前暂用 sdl。经过上面这些,我们的网络播放器终于可以工作了。那现在只剩下一个 wpf 句柄问题了。好在我看到了网上文章里面介绍了 vlc 播放器 c#开源代码,可以使用共享内存。但

5、是说的不够详细这两个开源项目都是用共享内存实现的。 参考此两篇文章。我的播放器终于可以播放网络的视频,音频,然后才 wpf 播放了。中间有 wpf 调用 c 方法的一些细节。至此我们的问题真的解决了吗?NO,因为我们回调函数调用共享内存显示,里面有很多问题,比如当我们关闭程序时会出现访问锁定内存等问题。此问题肯定是可以解决的。但是我们东拼西凑把问题解决了。 当此方案不是最好的。这 3 篇文章介绍了怎么使用 mediaelement 完美解决播放视频问题。播放器源码可以用网上下面是我的播放器 c 部分的代码/* 本播放器主要是解决 从优酷上播放视频。 是有多段网络视频组成一个完整视频。 解决方案

6、,开辟两个线程,一个线程从网络中读取数据包放入缓冲池(视频缓冲池和音频缓冲池) 一个线程从音频缓冲池读取数据播放。一个从视频缓冲池中读取播放.难点 1:av_read_frame 是读取 packet(包) 数据, 几包数据 组成 avframe(帧) 音频帧转换成 byte 存储起来 放入缓冲池 吃音频 byte可以直接放入音频流中播放 视频帧也是 byte 存储起来,此视频 byte数组可以转换为图片 PIX_FMT_RGB24 为了同步音视频,我们把没帧的最后一包的 pts 记录下来放入缓冲区*/ #include “stdafx.h“ #include “BonkerPlayer.h“

7、 #include #include #include extern “C“ #include “libavcodec/avcodec.h“ #include “libavformat/avformat.h“ #include “libswresample/swresample.h“ #include “libswscale/swscale.h“ #include /SDL #include “sdl/SDL.h“ #include “sdl/SDL_thread.h“ ;#define VideoBufferMaxSize 80/2048 /视频缓冲区最大值,大于此值 则不下载数据 #def

8、ine VideoBufferMinSize 20/1024 /视频缓冲区最小值,小于此值,则唤醒下载 #define AudioBufferMaxSize 80/2048 /音频缓冲区最大值,大于此值 则不下载数据 #define AudioBufferMinSize 20/1024 /音频缓冲区最小值,小于此值,则唤醒下载 #define SDL_AUDIO_BUFFER_SIZE 1024 /音频流的缓冲区/#define VideoType PIX_FMT_YUV420P /视频转换的格式 #define VideoType PIX_FMT_BGR24 /视频转换的格式#define

9、MAX_AUDIO_FRAME_SIZE 192000 / 1 second of 48khz 32bit audio /static char ErrorMsg100=“;/错误的提示信息int FileDuration=0;/视频的长度 单位秒int flag=100;/标识 播放,暂停,退出 0 退出,1 标识,2 暂停/声明了函数指针 DispalyVideoDele Fn=NULL;Uint32 audio_len; Uint8 *audio_pos;double currentAudioClock=0;/当前音频播放时间double currentVideoClock=0;/当前视

10、频播放时间double currentBufferClock=0;/当前以缓冲的时间,用于缓冲进度条/double currentPlayClock=0;/当前播放的时间,用于播放进度条double diffClock=0.2;/音视频相差的死区int CurrentVolume=SDL_MIX_MAXVOLUME/2;/当前声音的大小SDL_Thread *decodeTid=NULL;/解码线程 SDL_Thread *PlayVideoTid=NULL;/视频播放线程 SDL_Thread *PlayAudioTid=NULL;/音频播放线程/快进的参数bool isSeek=false

11、;/是否在快进int global_seek_index=0;/文件索引 快进double globle_seek_pos=0;/快进的地方/存储音频的队列typedef struct AudioItemUint8 *AudioData;/音频数据int Length;/音频长度double Pts;/时间戳AudioItem *Next;/尾部SDL_AudioSpec *wanted_spec; AudioQueueItem;typedef structAudioQueueItem *FirstItem;/队列头AudioQueueItem *LastItem;/队列位int Length

12、;/队列长度SDL_mutex *audioMutex;/用于同步两个线程同时操作队列的 互斥量SDL_cond *audioCond;/唤醒线程 AudioQueue;/存储视频的队列typedef struct VideoItemUint8 *VideoData;/音频数据int Width;/视频图片的宽度int Height;/视频图片的高度int Length;/视频长度double Pts;/时间戳VideoItem *Next;/尾部 VideoQueueItem;typedef structVideoQueueItem *FirstItem;/队列头VideoQueueItem

13、 *LastItem;/队列位int Length;/队列长度double BufferPts;/缓冲的 ptsSDL_mutex *videoMutex;/用于同步两个线程同时操作队列的 互斥量SDL_cond *videoCond;/唤醒线程 VideoQueue;VideoQueue *videoQueue=NULL;/视频队列 AudioQueue *audioQueue=NULL;/音频队列/清空视频队列void VideoQueueClear(VideoQueue *vq)VideoItem *item,*temp;SDL_LockMutex(vq-videoMutex);for

14、(item=vq-FirstItem; item!=NULL; item=temp)temp=item-Next;/av_free(item-VideoData);/释放 video 里面的数据av_free(item);vq-Length-;vq-FirstItem=NULL;vq-LastItem=NULL;SDL_UnlockMutex(vq-videoMutex); /清空音频队列void AudioQueueClear(AudioQueue *aq)AudioItem *item,*temp;SDL_LockMutex(aq-audioMutex);for (item=aq-Firs

15、tItem; item!=NULL; item=temp)temp=item-Next;/av_free(item-AudioData);/释放 video 里面的数据av_free(item-wanted_spec);av_free(item);aq-Length-;aq-FirstItem=NULL;aq-LastItem=NULL;SDL_UnlockMutex(aq-audioMutex); /初始化视频队列void VideoQueueInit(VideoQueue *vq)memset(vq, 0, sizeof(VideoQueue);/初始化首地址为 0vq-videoMute

16、x=SDL_CreateMutex();vq-videoCond=SDL_CreateCond(); /初始化音频队列void AudioQueueInit(AudioQueue *aq)memset(aq,0,sizeof(AudioQueue);aq-audioMutex=SDL_CreateMutex();aq-audioCond=SDL_CreateCond(); /向队列添加数据int VideoQueuePut(VideoQueue *vq,VideoQueueItem *item)int result=0;SDL_LockMutex(vq-videoMutex);/加锁if(vq-LengthFirstItem)/第一个 item 为 null 则队列是空

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号