按照策划要求,制作一个工具能够导出服战录像并让player.exe播放。
在简单分析了一下java端和C++端的数据结构之后,我认为在服务端直接构造录像文件并不可取,
同时发现在客户端存在在线播放录像的功能。
本次的需求和原有的在线播放录像的功能大致相似,唯一的区别是在线播放录像的数据通过协议
传入,而这次改为通过二进制文件传入。
因此我定下了如下方案:服务端将压缩后的数据通过二进制写入文件,同时在文件头部添加MZFRS
来让播放器知道这和普通的录像文件不一样。播放器打开这个类型的文件之后,通过转换将传入的
文件转换成播放器之前使用的那种可以播放的格式进行播放。
但是,
有坑。
坑1:在早期的测试中,服务端导出的文件客户端并不能读出具体数据。当时的我认为这是java语言
使用大端序而运行在IA(Intel,AMD)架构下的C++端使用小端序。先后采取了编写转换函数和使用
Java的ByteBuffer来转换字节序等操作。(这里还可以再展开一下说说我对字节序转换等的逐渐了解。)
实际上,公司内的marshal/unmarshal算法已经考虑了不同语言在不同平台的字节序问题。因此在
将数据序列化之后它的字节序就已经转换成了小端序。不需要手动转换。
这应该算得上是卡主我最长时间的一个坑,大概十多天的时间我都在盲目的尝试转换字节序等。
坑2:在发现不需要转换字节序之后,C++端的读取还是会出现问题,一批次导出的所有录像文件中,
偶然能有一两个是能够正常播放的。其他的则会出错。
通过单步调试,发现在底层库的一个函数那里,函数参数是引用变量,但是作为实参的被引用变量
的值并没有在函数执行之后如预期的发生改变。(在函数内,是确切的读到了正确值的。)
简单说,引用变量的地址和被引用变量的地址不一样。【正常情况下是一样的。毕竟引用只是一个
变量的别名】
一开始我以为这是公司底层库出的问题。后来则发现是客户端在读取的时候打开文件出了问题。
正常情况下打开一个二进制文件应该类似下面:
File.open(strFileName.c_str(),std::ios::in|std::ios::binary);
文件名后面的参数通过|来连接。
然而客户端错误的使用了||来连接两个参数,这样后面的二进制参数实际上没有生效。(参考短路与的效果)。因此是将这个二进制文件作为一个文本文件来读取了。如果遇到空行之类的就会出错。悲伤的是二进制的录像文件中有什么我们谁也不知道。因此只有少数几个幸运儿能够顺利读取了。
这就是我的第一个需求的解决方案。