写一个支持SMB的手机VR播放器(一):基础知识

手里有几个低成本的 CardBoard VR 塑料盒子,用来在手机上体验 VR 内容。由于本人拥有数个 NAS ,因此迫切需要一种方法播放上面的内容。
起因
从箱子角落翻出了几个叫做 xx 魔镜、xx VR 的 VR 盒子,他们都是 CardBoard 类型的 VR 盒子。CardBoard 是一种低成本的 VR 解决方案,它们使用手机计算并显示内容,人眼透过头盔上的两个菲涅尔镜片来观看手机屏幕,以此达到 VR 观感。
根据本博之前的文章可知,本博拥有多个低功耗 PT 挂机 NAS,通过 Samba(SMB)将它们挂载为远程磁盘,平日里使用起来极为方便。某年某月某日,一个偶然的机会,本博搞到了 1TB+ 的 VR 视频资源。
本博想把这些 VR 盒子利用起来,但找了一圈都没找到同时支持 SMB 与 VR 的安卓播放器。目前大部分支持 VR 视频的播放器应用(爱奇艺 VR 等)不支持 SMB,而大部分支持 SMB 的视频播放器应用不支持 VR 视频(eg: 画面反畸变处理等)。
所以,为了达成这个目标,只能自己写一个了。
名词解释
1.Samba 与 SMB
SMB 是一种文件共享传输协议,Windows 平台默认支持该协议。通过该协议,你可以在同一网络下的计算机中共享文件,并执行增删改查等操作。
Samba 是一个免费软件,用来在 Linux 上实现 SMB 协议。通过此软件,Windows 计算机就可以通过局域网访问 Linux SMB 目录,实现资源共享。Windows 资源管理器内置了对 SMB 目录的支持,因此通过 SMB 访问共享内容,要比 FTP 等省事得多。
2.VR 视频
VR 视频目前可以简单分为两类:全景视频与立体视频,前者可分为筒状
(非常少见)、180度/360度全景
、六面全景
(少见,一般会合成为 360 度视频)等,而立体视频可以分为上下
、左右
、红蓝
等。
3.畸变与反畸变
VR 透镜会使得图像发生畸变,这是因同时追求短焦、小体积、大视场角(FOV)而产生的一个光学问题,具体原因见『VR镜头抗畸变基本算法探讨』一文。
为了让人眼看到的图像为正常图像,播放器需要将图像做个反向畸变(大多数 VR SDK 均已实现),使得画面经过透镜畸变后显示正常(可以理解成 -1 + 1 = 0)。
大多数手机播放器虽然支持解码 VR 视频,但因缺少反畸变处理,直接使用 CardBoard 观看,画面会产生变形、扭曲、错位等。
技术实现
目前需要解决三个问题:
- 安卓设备访问 smb 内容;
- 将 smb 内容提供给上层播放器应用;
- 播放器应用解码、反畸变,最终输出画面。
问题 3 是最好解决的,可以直接在 Unity 中使用 CardBoard SDK + 播放器插件最好解决的。所以问题难点在于如何访问 Smb 内容并将其提供给 Unity。
根据对 ES 文件浏览器等软件的研究,发现它们的做法都是在 Android 端实现 smb to http 的转换服务,之后将 http 链接提供给播放器进行播放。
因此,想要实现我的目标,首先要在 Android 端用 Java 代码实现 smb to http 服务,之后将这些数据、方法等提供给 Unity C# 使用,他们的关系如图所示:
Unity 可以和 Java 进行交互,所以可以考虑将 Java 代码及接口封装到 Jar 包中引入 Unity。
验证
主要验证 Android 端是否可以访问 SMB Server,因此我引入了 smbj 插件,并写了段简单的 Java 代码验证文件浏览:
SMBClient client = new SMBClient();
try (Connection connection = client.connect("192.168.3.102"))
{
System.out.println("==================");
AuthenticationContext ac = new AuthenticationContext("shares","shares".toCharArray(),"/");
Session session = connection.authenticate(ac);
try(DiskShare share = (DiskShare) session.connectShare("d1_2"))
{
for (FileIdBothDirectoryInformation f : share.list("movies","*")){
//System.out.println("File:" + f.getFileName());
runOnUiThread(new Runnable() {
@Override
public void run() {
test.setText(test.getText() + "\r\n" + f.getFileName());
}
});
}
}
} catch (IOException e) {
e.printStackTrace();
}
以下是运行结果:
其他
本博是一个 Unity 脚本小子,而非专业的 Java 安卓开发。对于一些有开源解决方案的 Java 需求,本博将在验证开源解决方案使用的基础库的可行性后之后直接使用这些方案,不再花费时间重复造轮子。
这不是一个商业项目,它与本人的本职工作内容也无关,因此相关仓库将放置于本博交流群内的 Github 组织 —— 菜鸟生物圈下。另外,由于它出于兴趣开始,因此中途有很大可能放鸽子。