Skip to content

Commit 7716b9d

Browse files
xZisepaxcut
andauthored
patterns: Add support for smk (#399)
* patterns: Add support for smk * patterns: Use builtin function and separate SMK struct --------- Co-authored-by: paxcut <[email protected]>
1 parent ad1e300 commit 7716b9d

File tree

2 files changed

+219
-0
lines changed

2 files changed

+219
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi
156156
| Shell Link | `application/x-ms-shortcut` | [`patterns/lnk.hexpat`](patterns/lnk.hexpat) | Windows Shell Link file format |
157157
| shp | | [`patterns/shp.hexpat`](patterns/shp.hexpat) | ESRI shape file |
158158
| shx | | [`patterns/shx.hexpat`](patterns/shx.hexpat) | ESRI index file |
159+
| smk | | [`patterns/smk.hexpat`](patterns/smk.hexpat) | Smacker video file |
159160
| sup | | [`patterns/sup.hexpat`](patterns/sup.hexpat) | PGS Subtitle |
160161
| SPIRV | | [`patterns/spirv.hexpat`](patterns/spirv.hexpat) | SPIR-V header and instructions |
161162
| STDF | | [`patterns/stdfv4.hexpat`](patterns/stdfv4.hexpat) | Standard test data format for IC testers |

patterns/smk.hexpat

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
#pragma author xZise
2+
#pragma description Smacker video file
3+
#pragma endian little
4+
#pragma magic [53 4D 4B 32] @ 0x0
5+
6+
import std.core;
7+
import std.io;
8+
import std.mem;
9+
10+
bitfield HeaderFlags {
11+
ContainsRingFrame : 1;
12+
YInterlaced : 1;
13+
YDoubled : 1;
14+
padding : 29;
15+
};
16+
17+
bitfield HeaderAudioFlags {
18+
isCompressed : 1;
19+
hasAudio : 1;
20+
is16BitAudio : 1;
21+
isStereo : 1;
22+
soundDecompression : 2;
23+
padding : 2;
24+
audioSampleRate : 24;
25+
};
26+
27+
fn format_frame_rate(auto frame_rate) {
28+
float fps;
29+
if (frame_rate > 0) {
30+
fps = 1000.0 / frame_rate;
31+
} else if (frame_rate < 0) {
32+
fps = 100000.0 / (-frame_rate);
33+
} else {
34+
fps = 10;
35+
}
36+
return std::format("{} fps", fps);
37+
};
38+
39+
struct Header {
40+
char Signature[4];
41+
u32 Width;
42+
u32 Height;
43+
u32 FrameCount;
44+
s32 FrameRate [[format("format_frame_rate")]];
45+
HeaderFlags Flags;
46+
u32 AudioSize[7];
47+
u32 TreesSize;
48+
u32 MMap_Size;
49+
u32 MClr_Size;
50+
u32 Full_Size;
51+
u32 Type_Size;
52+
HeaderAudioFlags AudioRate[7];
53+
padding[4];
54+
};
55+
56+
fn format_size(auto size) {
57+
if (size.keyframe != 0) {
58+
return std::format("[K] {} B", size.size);
59+
}
60+
return std::format("[ ] {} B", size.size);
61+
};
62+
63+
bitfield Size {
64+
keyframe : 1;
65+
padding : 1;
66+
dwordCount : 30;
67+
68+
u32 size = dwordCount * 4;
69+
} [[format("format_size")]];
70+
71+
72+
bitfield FrameType {
73+
ContainsPaletteRecord : 1;
74+
ContainsAudioTrack0 : 1;
75+
ContainsAudioTrack1 : 1;
76+
ContainsAudioTrack2 : 1;
77+
ContainsAudioTrack3 : 1;
78+
ContainsAudioTrack4 : 1;
79+
ContainsAudioTrack5 : 1;
80+
ContainsAudioTrack6 : 1;
81+
};
82+
83+
fn format_palette_copy_only(auto copy_only) {
84+
return std::format("copy: {0}", copy_only.copy);
85+
};
86+
87+
bitfield PaletteCopyOnly {
88+
copy: 7;
89+
mode: 1;
90+
} [[format("format_palette_copy_only")]];
91+
92+
fn format_palette_copy_skip(auto copy_skip) {
93+
return std::format("copy: {0}, skip: {1}", copy_skip.copy, copy_skip.skip);
94+
};
95+
96+
bitfield PaletteCopySkip {
97+
copy: 6;
98+
mode: 2;
99+
skip: 8;
100+
} [[format("format_palette_copy_skip")]];
101+
102+
bitfield PaletteColor {
103+
blue: 6 [[color("0000FF")]];
104+
mode: 2;
105+
green: 6 [[color("00FF00")]];
106+
padding: 2;
107+
red: 6 [[color("FF0000")]];
108+
padding: 2;
109+
110+
u8 r8 = red << 2 | red >> 4;
111+
u8 g8 = green << 2 | green >> 4;
112+
u8 b8 = blue << 2 | blue >> 4;
113+
} [[hex::inline_visualize("color", r8, g8, b8, 0xff)]];
114+
115+
fn format_palette_chunk_block(auto entry) {
116+
u8 first = entry.type;
117+
if (first & 0x80 == 0x80) {
118+
return format_palette_copy_only(entry.copy);
119+
} else if (first & 0x40 == 0x40) {
120+
return format_palette_copy_skip(entry.copy_skip);
121+
} else {
122+
return std::format("color: 0x{0:02x}{1:02x}{2:02x}", entry.color.r8, entry.color.g8, entry.color.b8);
123+
}
124+
};
125+
126+
enum PaletteChunkBlockType: u8 {
127+
Color = 0x00 ... 0x3F,
128+
CopySkip = 0x40 ... 0x7F,
129+
CopyOnly = 0x80 ... 0xFF
130+
};
131+
132+
// Unfortunately the match expression does not support ranges, so this is a helper for the following code:
133+
// PaletteChunkBlockType type = std::mem::read_unsigned($, 1)
134+
fn get_palette_chunk_block_type() {
135+
u8 type = std::mem::read_unsigned($, 1);
136+
if (type & 0x80 == 0x80) {
137+
return PaletteChunkBlockType::CopyOnly;
138+
} else if (type & 0x40 == 0x40) {
139+
return PaletteChunkBlockType::CopySkip;
140+
} else {
141+
return PaletteChunkBlockType::Color;
142+
}
143+
};
144+
145+
fn get_last_position() {
146+
PaletteChunkBlockType type = get_palette_chunk_block_type();
147+
match (type) {
148+
(PaletteChunkBlockType::CopyOnly): return $;
149+
(PaletteChunkBlockType::CopySkip): return $ + 1;
150+
(PaletteChunkBlockType::Color): return $ + 2;
151+
}
152+
};
153+
154+
struct PaletteChunkBlock {
155+
PaletteChunkBlockType type = get_palette_chunk_block_type() [[export]];
156+
match (type) {
157+
(PaletteChunkBlockType::CopyOnly): PaletteCopyOnly copy;
158+
(PaletteChunkBlockType::CopySkip): PaletteCopySkip copy_skip;
159+
(PaletteChunkBlockType::Color): PaletteColor color;
160+
}
161+
} [[format("format_palette_chunk_block")]];
162+
163+
struct PaletteChunk {
164+
u8 length;
165+
u128 end = $ + length * 4 - 1;
166+
PaletteChunkBlock blocks[while(get_last_position() < end)];
167+
if ($ < end) {
168+
padding[end - $];
169+
}
170+
};
171+
172+
struct AudioTrack<auto trackIndex> {
173+
u32 length;
174+
if (parent.parent.header.AudioRate[trackIndex].isCompressed) {
175+
u32 decompressedSize;
176+
}
177+
u8 trackData[length - ($ - addressof(this))];
178+
};
179+
180+
struct FramesData {
181+
u32 frame_index = std::core::array_index();
182+
u32 size = parent.sizes[frame_index].size;
183+
if (parent.frameTypes[frame_index].ContainsPaletteRecord) {
184+
PaletteChunk palette;
185+
}
186+
if (parent.frameTypes[frame_index].ContainsAudioTrack0) {
187+
AudioTrack<0> audioTrack0;
188+
}
189+
if (parent.frameTypes[frame_index].ContainsAudioTrack1) {
190+
AudioTrack<1> audioTrack1;
191+
}
192+
if (parent.frameTypes[frame_index].ContainsAudioTrack2) {
193+
AudioTrack<2> audioTrack2;
194+
}
195+
if (parent.frameTypes[frame_index].ContainsAudioTrack3) {
196+
AudioTrack<3> audioTrack3;
197+
}
198+
if (parent.frameTypes[frame_index].ContainsAudioTrack4) {
199+
AudioTrack<4> audioTrack4;
200+
}
201+
if (parent.frameTypes[frame_index].ContainsAudioTrack5) {
202+
AudioTrack<5> audioTrack5;
203+
}
204+
if (parent.frameTypes[frame_index].ContainsAudioTrack6) {
205+
AudioTrack<6> audioTrack6;
206+
}
207+
u8 video[size - ($ - addressof(this))];
208+
};
209+
210+
struct SMK {
211+
Header header;
212+
Size sizes[header.FrameCount];
213+
FrameType frameTypes[header.FrameCount] ;
214+
u8 trees[header.TreesSize];
215+
FramesData frames[header.FrameCount];
216+
};
217+
218+
SMK smk @ 0x00 [[inline]];

0 commit comments

Comments
 (0)