前记
作为一篇没啥内在的文章,我记在博客中主要有两点:1.总结 2.希望刚接触的FFmpeg的朋友能少绕路,希望它起到一定作用。
在第一阶段学习中,对FFmpeg的精华几乎没有涉及,主要是在ios下实现了一个能播放视频的Demo。Demo目前再声音和图像同步方面做的不够出色,这也是我目前未解决的问题。
输出图像
我在编译FFmpeg lib时就使用了iFrameExtractor作为样例。使用一个时钟输出下一帧的图像,然后显示图像就能显示。就这样。。。。
参考
[1]iFrameExtractor on GitHub
[2]An ffmpeg and SDL Tutorial(第一章,第二章)
声音呢?
FFmpeg输出声音需要借助平台音频库,针对于ios你可以是用AudioQueue(我用的是这个,我还会告诉你一篇很好的教程),OpenAL。
参考
[1]Bear實驗室: iOS用AudioToolbox播放網路收音機 (使用FFmpeg) [Part 2][Part 3]
[2]《Learing Core Audio》Chapter 4 Recording
[3]《Learing Core Audio》Chapter 5 PlayBack
节奏一致
我们希望我们的图像声音保持同步,iFrameExtractor的作者在自己的WordPress上说明了方法,在GitHub上也有Demo做到了这一点。
我很奇怪为什么WordPress也得FQ?
参考
[1]Programming FFmpeg in iOS (1) (2) (3)
[2]iOSFFmpeg-master on GitHub
总结
其实实现大自同步并不难,我是说“大自”,好吧,其实我现在也知道大自同步。下面我来说说我的实现:
第一点:如果你同时播放声音和图片,你会发现图片总是跑在音乐的前面,所以我们得将解码得到的图片存起来,减慢它的节奏。
第二点:你得知道pts,dts。pts =Presentation timestamp in AVStream->time_base units;我们将使用AVPacket中的pts,它意味着这个Frame也就是图片应该在什么时候显示在屏幕上。与主时钟同步需要将pts装换成second。
1 double _second = pReadPkt.pts * av_q2d(pFormatCtx->streams[VideoStreamIndex]->time_base);
1 //程序主时钟 2 -(void)refreshCurrentTime{ 3 if (pCurrentTime){ 4 [pCurrentTime release]; 5 pCurrentTime = nil; 6 } 7 if (!pCurrentTime){ 8 pCurrentTime = [[NSDate date]retain]; 9 } 10 } 11 12 -(void)loopVideoOutput:(NSTimer *)timer { 13 14 15 NSTimeInterval elapsedTime = [pCurrentTime timeIntervalSinceNow]; 16 pCurrentSecond -= elapsedTime; 17 [self refreshCurrentTime]; 18 }
综上来看一段伪代码基本上就是参考[1]的奥义了:
1 尝试策略: 2 //我缓存的图片的时钟是否小于主时钟 3 if([self objectAtIndex:0].second < _syncSecond) 4 //是的,读取它,并从队列中删除 5 [self removeobjectAtIndex:0]; 6 //输出图片更新 7 poutImage = obj[0]; 8 else 9 //不,还没轮到它显示 do nothing 10 [self notRead]; 11 //ImageView更新显示 12 controller.imageView.image = pOutImage;
这样大自的同步就做到了,你会发现这样的实现图片会快1~2秒,蛋疼。
在写Demo的时候发现对AVPicture存取的封装好坏会对程序影响很大,参考[2]做出了很好的展示。
第二阶段的探索
完全同步并不是接下来的主要方向,在第一阶段我尝试使用过OpenAL做为音频输出,但是得到只有杂音~~~~~这将会是一个棘手的问题。
当你刚开始在iOS上学习FFmpeg的时候,使用imageView.image = pOutImage是一个很好的选择,除非你一开始就会Opengl,这样你能大大减少代码量。但是Opengl有它的伟大之处,它能输出YUV格式的图片,否则你只能把它变成RGB,然后输出。。。。
还有一点学习两者,能使你的代码更加通用。。。。因为两者都是跨平台的。
同步问题却是存在。。。所以解决它。
最后
enjoy it!!!