美文网首页
底层 - 直读官方 - 旧地图中的JPEG解析

底层 - 直读官方 - 旧地图中的JPEG解析

作者: 1f872d1e3817 | 来源:发表于2018-08-29 12:57 被阅读0次

大话2的地图文件分为新地图和旧地图,分别在newscene和scene文件夹下。

新旧两种地图格式有很大的不同。

地图的相关资料首先要感谢王大理Wangdali前辈,没有他的帮助,我自己不可能解开map数据包。

此处引用wangdali对大话2旧地图数据格式的整理

Map File Old Format
Dali Wang <wdl@sina.com>
2004-05-09 起稿 @Changchun
2004-05-10 修改 @Changchun
2006-02-19 修改 @Haikou

=======================MAP HEAD===============================
4字节 XPAM(MAPX)
4字节 地图的宽度
4字节 地图的高度

4*n字节 地图单元的引索 n=地图的宽度/640*2 * 地图高度/480*2
4字节 多出的一个地图单元引索,即结束引索,也就是文件的大小。

4字节 HGPJ (JPGH)
4字节 JPG头的大小
n字节 数据内容 n=JPG头的大小,不包括前面8字节。

==============================================================

4字节 地图单元引索的开始位置,也是KSAM的数量。

4字节 GAMI (IMAG)
4字节 大小(153600),正好是320x240x2。
n字节 数据,不包括前面8字节。

4字节 GEPJ (JPEG)
4字节 JPEG单元大小,不包括这8字节。
2字节 单元地图的宽度
2字节 单元地图的高度
n字节 地图数据

4字节 KSAM (MASK)
4字节 大小(不定)
n字节 数据,不包括前面8字节。
:
4字节 KSAM (MASK)
4字节 大小(不定)
n字节 数据,不包括前面8字节。


4字节 KOLB (BLOK)
4字节 大小(9600)
n字节 数据,不包括前面8字节。

4字节 LLEC (CELL)
4字节 大小(192)
n字节 数据,不包括前面8字节。

4字节 GIRB (BRIG)
4字节 大小(不定)
n字节 数据,不包括前面8字节。

8字节 结束单元。

==============================================================

XPAM (MAPX) 地图文件头
Index       图象单元引索
HGPJ (JPGH) 图象JPEG Head

GAMI (IMAG) 只有1028.map地图含有这个单元。
GEPJ (JPEG) 图象数据
KSAM (MASK)
:
KSAM (MASK)
KOLB (BLOK) 遮掩规则,一比特代表一个地图像素。
LLEC (CELL) 地图规则,一字节代表一个游戏坐标。
GIRB (BRIG) 光亮规则
:
:
:
GAMI (IMAG) 只有1028.map地图含有这个单元。
GEPJ (JPEG) 图象数据
KSAM (MASK)
:
KSAM (MASK)
KOLB (BLOK) 遮掩规则,一比特代表一个地图像素。
LLEC (CELL) 地图规则,一字节代表一个游戏坐标。
GIRB (BRIG) 光亮规则
***********************************************************************

旧地图

网上的现有程序大多只能解析出新地图,是因为云风对旧地图的JPEG数据进行了特殊的处理,普通的JPEG DECODER无法解析。

在解析旧地图时,需要首先提取出JPEG HEAD,然后分别和各单元的JPEG BODY结合。

在旧地图中,JPEG在解析每一个MCU前,需要提前读取YCbCr的DC数据,而不是像普通的JPEG文件那样,继承上个MCU单元的处理后的DC值。换句话说,是云风把每个MCU的所需的DC值,提取到了MCU数据之前,因此在普通JPEG DECODER看来,本该是下一个MCU数据的起始位置的地方,放上了6字节的未知数据(即3个DC值),也因此导致普通的JPEG DECODER无法解析旧地图的JPEG。那么我们只需在每进行到一个新的MCU时,获取6字节的DC值就可以了。
云风的JPEG文档

for (i=0;i<VDU;i+=16) {
    jpeg_stream+=(jpeg_bit+7)/8;
    jpeg_DC[0]=*jpeg_stream_short++;  // 关键
    jpeg_DC[1]=*jpeg_stream_short++;  // 关键
    jpeg_DC[2]=*jpeg_stream_short++;  // 关键
    jpeg_bit=*jpeg_stream++;

    for (j=0;j<HDU;j+=16) {
        if (*(jpeg_stream+(jpeg_bit+7)/8)==0xff) {
            jpeg_stream+=(jpeg_bit+7)/8;
            jpeg_bit=0;
            while (*jpeg_stream!=0xff) ++jpeg_stream;
                ++jpeg_stream;
                jpeg_DC[0]=jpeg_DC[1]=jpeg_DC[2]=0;
        }
        jpeg_decode_DU(jpeg_ybuf,0);
        jpeg_decode_DU(jpeg_ybuf+64,0);
        jpeg_decode_DU(jpeg_ybuf+128,0);
        jpeg_decode_DU(jpeg_ybuf+192,0);
        jpeg_decode_DU(jpeg_cbbuf,1);
        jpeg_decode_DU(jpeg_crbuf,2);
        YCbCr411((unsigned short*)(output_buffer+i*pitch)+j,pitch);
    }
}

把这段程序移植到云风的JPEG Decoder上,就可以解析了旧地图的JPEG了。

我自己本来是打算pure python的,然而经过实验,用python去解析JPEG实在是太慢了,因此有关数据解析的关键程序,全部用C写,然后打包成dll供python调用。

附加:

经过验证,所有的旧地图的JPEG HEAD都是相同的,也就是说,把map A的JPEG HEAD替换成map B的,A仍然能正确解析各单元的JPEG图片。
在我实验中,有一个现象十分奇怪。小地图文件的单个单元读取速度要比大地图的单个单元读取速度快很多,当我把大地图的JPEG HEAD替换成小的时候,大地图的读取速度也变的一样快了。
Why??
如果JPEG HEAD不相同,那不应该解析出正确的图片;如果相同,那为什么速度会变快?

相关文章

网友评论

      本文标题:底层 - 直读官方 - 旧地图中的JPEG解析

      本文链接:https://www.haomeiwen.com/subject/kjshwftx.html