缘起
Android上硬件编解码一直是个老大难问题,就解码来说,硬解码本身并不困难,只要按照MediaCodec的流程开发即可。但由于系统碎片化,硬件规格不一致,硬件解码会到黑屏,花屏,绿屏之类的显示问题。为了不招致用户投诉,我们在做视频解码的时候不太敢开启硬件加速,一般会采用保守策略,即以软解为主,优先保证画面正常,但牺牲了性能。
一般解决这个问题的方案是使用黑(白)机型名单下发配置(如:腾讯视频),或者暴露开关让用户手动去控制是否走硬件解码(如:bilibili)。
使用机型黑(白)名单有一定的作用,但其问题也显而易见:
- 需要浪费大量的人力,精力进行机型测试,去维护,发布名单
- 覆盖度偏低,一般只覆盖TOP机型
- 缺乏时效性,例如新机型上市不能及时跟进
- 不一定准确,因为硬解是否成功,跟视频源也有很大关系,同一个机型可能解这个视频不成功,另外一个视频又是成功的。按照机型\u0026quot;一刀切\u0026quot;的前提是要保证视频规格一致,这样才最健壮。
通过开关让用户切换体验太差,尤其是“抖音”之类的短视频App,总不能每个界面加个开关让用户去切换解码器这么深奥的东西吧,从用户角度讲,我为什么要关心这个什么解码器怎么设置,只要视频能正常看就行。
仔细思考一下,我们其实可以实现自动化的检测,即模拟人工检测流程,把样本视频各软硬解一遍,然后对比他们的解码结果(图片)就能够知道硬解码是否能跑通。解码的流程轻车熟路,那么这里的关键问题就是我们如何进行图片对比?如何量化图片的差异度?
图片检索技术
图片对比其实跟\u0026quot;以图搜图\u0026quot;本质上是同一种技术,通常有几种做法MSE,均值哈希,色彩直方图以及OpenCV里面一些提取图像特征的高级算法,如Sift,Surf等。基于移动端的运行效率,安装包大小,以及需求本身考虑,我们放弃引入OpenCV。MSE 属于逐像素对比,对像素值要求过于严格,太简单粗暴,色彩直方图不太好量化差异度。基于以上考虑,我们选择图像哈希算法,它可以输出汉明距离,方便量化软硬解结果的差异度。
哈希算法有三种,平均哈希,感知哈希和差异度哈希,基于准确度考虑,我们选择实现较复杂一些的感知哈希算法。另基于性能考虑,我们在Android平台上使用C++实现算法,通过JNI接口给Java调用。Java层输入Android的Bitmap对象,输出为图片指纹,再通过对比指纹的汉明距离,我们即可判断出来解码是否正常。
Java层接口签名如下: