视频、动画的原理就是逐帧播放
先看一段伪代码:
class VideoPlayer{ void init(string mp4File) { auto textures = ffmpeg.decode(mp4File); for(int i=0; i< textures.size(); i++){ this->_textureMaps[i]=textures.at(i); } } void play() { this->_state="playing"; } void update(float dt){ if(this->_state == "playing"){ this->frameIndex++; auto frame = video->getFrame(); this->render(frame); } } Texture* getFrame(){ return this->_textureMaps[this->frameIndex]; } }
这段代码是最初我对视频的一个理解,大致的思路就是将视频的每一帧画面都解析出来后,以帧为key,保存到一个map中,当播放的时候,依次按照顺序从头开始依次播放。
这么实现视频播放的确能看到效果,视频的确播放起来了。
存在的问题
上边的思路,其实存在非常多的问题。
内存会爆表
如果一个60fps的10秒时长视频,分辨率是 1920 * 1080 分辨率,如果解析为RGBA8888,大概占用的内存大小为60x10x1920x1080x4字节这么大,当然你可以给视频减配,但是这个问题仍旧存在,本质是缓存cache导致的。
导致严重的卡顿
因为视频的解码是一个密集运算的逻辑,当然也可以通过多线程解决这个问题。
播放速率
每一帧所处的时间,在解码结果里面是有这个信息的,因为播放依赖update驱动,需要自己根据update的dt参数,自己计算当前走到了第几帧,这里面就牵扯到了同步的问题,有很多思路,后续会逐步展开。
音频怎么同步
上述代码中其实也没有说明音频是如何同步的,在FFMpeg中,音视频都是一个stream,我们需要做的就是拿到这个steam之后,按照自己的需求处理,但是因为音视频的处理方式是不同的,所以这里又牵扯到了同步问题
总结
初次接触音视频开发,可以看到细节还是非常多的,经过我的深入思考和多方面的请教,在主线程中解码视频并立即播放,这种方式存在大量的弊端,所以专业的音视频开发者都不会这么搞,多线程是肯定的,其次,关于cache,一般都会做容量的限制,像伪代码里面这种做法,会被人笑掉大牙的。