]>
Commit | Line | Data |
---|---|---|
606c448e KS |
1 | use std::io::SeekFrom; |
2 | use nihav_core::demuxers::*; | |
3 | ||
4 | const SMK_FLAG_LOOP_FRAME: u32 = 0x01; | |
5 | ||
6 | const SMK_FRAME_FLAG_PALETTE: u8 = 0x01; | |
7 | ||
8 | const SMK_AUD_FLAG_PACKED: u8 = 0x80; | |
9 | const SMK_AUD_FLAG_PRESENT: u8 = 0x40; | |
10 | const SMK_AUD_FLAG_16BIT: u8 = 0x20; | |
11 | const SMK_AUD_FLAG_STEREO: u8 = 0x10; | |
12 | const SMK_AUD_FLAG_BINKAUD_RDFT: u8 = 0x08; | |
13 | const SMK_AUD_FLAG_BINKAUD_DCT: u8 = 0x04; | |
14 | ||
15 | const NUM_AUDIO_TRACKS: usize = 7; | |
16 | ||
17 | const PAL_SIZE: usize = 768; | |
18 | ||
19 | const SMK_DEFAULT_PAL: [u8; 64] = [ | |
20 | 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, | |
21 | 0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C, | |
22 | 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D, | |
23 | 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D, | |
24 | 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E, | |
25 | 0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE, | |
26 | 0xC3, 0xC7, 0xCB, 0xCF, 0xD3, 0xD7, 0xDB, 0xDF, | |
27 | 0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF | |
28 | ]; | |
29 | ||
30 | #[derive(Clone,Copy)] | |
31 | struct AudioTrack { | |
32 | size: u32, | |
33 | flags: u8, | |
34 | srate: u32, | |
35 | id: usize, | |
36 | } | |
37 | ||
38 | impl AudioTrack { | |
39 | fn new() -> Self { | |
40 | Self { size: 0, flags: 0, srate: 0, id: 0 } | |
41 | } | |
42 | fn is_present(&self) -> bool { | |
43 | (self.flags & SMK_AUD_FLAG_PRESENT) != 0 | |
44 | } | |
45 | fn add_stream(&mut self, strmgr: &mut StreamManager, str_id: usize) -> DemuxerResult<()> { | |
46 | let channels = if (self.flags & SMK_AUD_FLAG_STEREO) != 0 { 2 } else { 1 }; | |
47 | let codecname = if (self.flags & SMK_AUD_FLAG_BINKAUD_RDFT) != 0 { | |
48 | "bink-audio-rdft" | |
49 | } else if (self.flags & SMK_AUD_FLAG_BINKAUD_DCT) != 0 { | |
50 | "bink-audio-dct" | |
51 | } else if (self.flags & SMK_AUD_FLAG_PACKED) != 0 { | |
52 | "smacker-audio" | |
53 | } else { | |
54 | "pcm" | |
55 | }; | |
56 | let soniton = if (self.flags & SMK_AUD_FLAG_16BIT) != 0 { SND_S16_FORMAT } else { SND_U8_FORMAT }; | |
57 | let ahdr = NAAudioInfo::new(self.srate, channels, soniton, 1); | |
58 | let ainfo = NACodecInfo::new(codecname, NACodecTypeInfo::Audio(ahdr), None); | |
59 | let res = strmgr.add_stream(NAStream::new(StreamType::Audio, (str_id + 1) as u32, ainfo, 1, self.srate)); | |
60 | validate!(res.is_some()); | |
61 | self.id = res.unwrap(); | |
62 | ||
63 | Ok(()) | |
64 | } | |
65 | } | |
66 | ||
67 | struct SmackerVideoDemuxer<'a> { | |
68 | src: &'a mut ByteReader<'a>, | |
69 | frames: usize, | |
70 | pts_inc: u64, | |
71 | cur_pts: u64, | |
72 | ainfo: [AudioTrack; NUM_AUDIO_TRACKS], | |
73 | frame_sizes: Vec<u32>, | |
74 | frame_flags: Vec<u8>, | |
75 | video_id: usize, | |
76 | start: u64, | |
77 | cur_frame: usize, | |
78 | queued_packets: Vec<NAPacket>, | |
79 | pal: [u8; PAL_SIZE], | |
80 | } | |
81 | ||
82 | /*macro_rules! mktag { | |
83 | ($a:expr, $b:expr, $c:expr, $d:expr) => ({ | |
84 | (($a as u32) << 24) | (($b as u32) << 16) | (($c as u32) << 8) | ($d as u32) | |
85 | }); | |
86 | ($arr:expr) => ({ | |
87 | (($arr[0] as u32) << 24) | (($arr[1] as u32) << 16) | (($arr[2] as u32) << 8) | ($arr[3] as u32) | |
88 | }); | |
89 | }*/ | |
90 | ||
91 | fn get_pts_inc(val: i32) -> u64 { | |
92 | if val > 0 { (val as u64) * 100 } | |
93 | else if val < 0 { (-val as u64) } | |
94 | else { 1 } | |
95 | } | |
96 | ||
97 | impl<'a> DemuxCore<'a> for SmackerVideoDemuxer<'a> { | |
33b5a8f0 | 98 | fn open(&mut self, strmgr: &mut StreamManager, _seek_idx: &mut SeekIndex) -> DemuxerResult<()> { |
606c448e KS |
99 | let src = &mut self.src; |
100 | let mut magic: [u8; 4] = [0; 4]; | |
101 | src.read_buf(&mut magic)?; | |
102 | validate!((&magic == b"SMK2") || (&magic == b"SMK4")); | |
103 | let width = src.read_u32le()? as usize; | |
104 | let height = src.read_u32le()? as usize; | |
105 | self.frames = src.read_u32le()? as usize; | |
106 | let pts_inc = src.read_u32le()? as i32; | |
107 | let flags = src.read_u32le()?; | |
108 | validate!((width > 0) && (height > 0) && (self.frames > 0)); | |
109 | self.pts_inc = get_pts_inc(pts_inc); | |
110 | ||
111 | if (flags & SMK_FLAG_LOOP_FRAME) != 0 { | |
112 | self.frames += 1; | |
113 | } | |
114 | ||
115 | for i in 0..NUM_AUDIO_TRACKS { | |
116 | self.ainfo[i].size = src.read_u32le()?; | |
117 | } | |
118 | let treesize = src.read_u32le()? as usize; | |
119 | ||
120 | let mut treedata: Vec<u8> = Vec::with_capacity(treesize + 20); | |
121 | treedata.resize(treesize + 24, 0); | |
122 | let hdr = &mut treedata[0..4]; | |
123 | hdr.copy_from_slice(&magic); | |
124 | let flg = &mut treedata[4..8]; | |
125 | flg[0] = (flags & 0xFF) as u8; | |
126 | flg[1] = (flags >> 8) as u8; | |
127 | flg[2] = (flags >> 16) as u8; | |
128 | flg[3] = (flags >> 24) as u8; | |
129 | src.read_buf(&mut treedata[8..][..16])?; | |
130 | ||
131 | for i in 0..NUM_AUDIO_TRACKS { | |
132 | self.ainfo[i].srate = src.read_u24le()?; | |
133 | self.ainfo[i].flags = src.read_byte()?; | |
134 | } | |
135 | ||
136 | src.read_skip(4)?; | |
137 | ||
138 | self.frame_sizes.resize(self.frames, 0); | |
139 | self.frame_flags.resize(self.frames, 0); | |
140 | for i in 0..self.frames { | |
141 | self.frame_sizes[i] = src.read_u32le()?; | |
142 | } | |
143 | for i in 0..self.frames { | |
144 | self.frame_flags[i] = src.read_byte()?; | |
145 | } | |
146 | ||
147 | src.read_buf(&mut treedata[24..])?; | |
148 | ||
149 | let vhdr = NAVideoInfo::new(width, height, false, PAL8_FORMAT); | |
150 | let vinfo = NACodecInfo::new("smacker-video", NACodecTypeInfo::Video(vhdr), Some(treedata)); | |
151 | let res = strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, 100000)); | |
152 | validate!(res.is_some()); | |
153 | self.video_id = res.unwrap(); | |
154 | ||
155 | for i in 0..NUM_AUDIO_TRACKS { | |
156 | if self.ainfo[i].is_present() { | |
157 | self.ainfo[i].add_stream(strmgr, i)?; | |
158 | } | |
159 | } | |
160 | ||
161 | self.start = src.tell(); | |
162 | self.cur_frame = 0; | |
163 | self.reset_state(); | |
d24468d9 | 164 | |
606c448e KS |
165 | Ok(()) |
166 | } | |
167 | fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> { | |
168 | if !self.queued_packets.is_empty() { | |
169 | let pkt = self.queued_packets.pop().unwrap(); | |
170 | return Ok(pkt); | |
171 | } | |
172 | if self.cur_frame >= self.frames { return Err(DemuxerError::EOF); } | |
173 | ||
174 | let mut payload_size = (self.frame_sizes[self.cur_frame] & !3) as usize; | |
175 | let frame_flags = self.frame_flags[self.cur_frame]; | |
176 | if (frame_flags & SMK_FRAME_FLAG_PALETTE) != 0 { | |
177 | let chunk_size = (self.src.read_byte()? as usize) * 4; | |
178 | validate!(chunk_size > 0); | |
179 | validate!(payload_size >= chunk_size); | |
180 | payload_size -= chunk_size; | |
7e6086e5 | 181 | let oldpal = self.pal; |
606c448e KS |
182 | let mut idx = 0; |
183 | let endpos = self.src.tell() + (chunk_size as u64) - 1; | |
184 | while idx < 256 { | |
185 | let op = self.src.read_byte()?; | |
186 | if (op & 0x80) != 0 { | |
187 | idx += ((op & 0x7F) as usize) + 1; | |
188 | } else if (op & 0x40) != 0 { | |
189 | let start = self.src.read_byte()? as usize; | |
190 | let len = ((op & 0x3F) as usize) + 1; | |
191 | validate!(idx + len <= 256); | |
192 | for i in 0..len*3 { | |
193 | self.pal[idx * 3 + i] = oldpal[start * 3 + i]; | |
194 | } | |
195 | idx += len; | |
196 | } else { | |
197 | let ix0 = op as usize; | |
198 | let ix1 = (self.src.read_byte()? & 0x3F) as usize; | |
199 | let ix2 = (self.src.read_byte()? & 0x3F) as usize; | |
200 | self.pal[idx * 3 + 0] = SMK_DEFAULT_PAL[ix0]; | |
201 | self.pal[idx * 3 + 1] = SMK_DEFAULT_PAL[ix1]; | |
202 | self.pal[idx * 3 + 2] = SMK_DEFAULT_PAL[ix2]; | |
203 | idx += 1; | |
204 | } | |
205 | } | |
206 | validate!(self.src.tell() <= endpos); | |
207 | if self.src.tell() < endpos { | |
208 | let skip_size = endpos - self.src.tell(); | |
209 | self.src.read_skip(skip_size as usize)?; | |
210 | } | |
211 | } | |
212 | ||
213 | let ts = NATimeInfo::new(Some(self.cur_pts), None, None, 1, 100000); | |
214 | for i in 0..NUM_AUDIO_TRACKS { | |
215 | if ((frame_flags >> (i + 1)) & 1) == 0 { continue; } | |
606c448e KS |
216 | let size = self.src.read_u32le()? as usize; |
217 | validate!(size > 4); | |
218 | validate!(payload_size >= size); | |
219 | payload_size -= size; | |
dc19613e KS |
220 | if !self.ainfo[i].is_present() { |
221 | self.src.read_skip(size - 4)?; | |
222 | continue; | |
223 | } | |
606c448e KS |
224 | let strres = strmgr.get_stream(self.ainfo[i].id); |
225 | validate!(strres.is_some()); | |
226 | let stream = strres.unwrap(); | |
227 | let pkt = self.src.read_packet(stream.clone(), ts, true, size - 4)?; | |
228 | self.queued_packets.push(pkt); | |
229 | } | |
230 | self.queued_packets.reverse(); | |
231 | ||
232 | let mut buf: Vec<u8> = Vec::with_capacity(PAL_SIZE + payload_size); | |
233 | buf.resize(PAL_SIZE, 0); | |
234 | buf.copy_from_slice(&self.pal[0..]); | |
235 | if payload_size > 0 { | |
236 | buf.resize(PAL_SIZE + payload_size, 0); | |
237 | self.src.read_buf(&mut buf[PAL_SIZE..])?; | |
238 | } | |
239 | ||
240 | let strres = strmgr.get_stream(self.video_id); | |
241 | validate!(strres.is_some()); | |
242 | let stream = strres.unwrap(); | |
243 | let keyframe = (self.frame_sizes[self.cur_frame] & 1) != 0; | |
244 | let pkt = NAPacket::new(stream, ts, keyframe, buf); | |
245 | ||
246 | self.cur_frame += 1; | |
247 | self.cur_pts += self.pts_inc; | |
248 | ||
249 | Ok(pkt) | |
250 | } | |
33b5a8f0 | 251 | fn seek(&mut self, time: u64, _seek_idx: &SeekIndex) -> DemuxerResult<()> { |
606c448e KS |
252 | if time == 0 { |
253 | let start = self.start; | |
254 | self.src.seek(SeekFrom::Start(start))?; | |
255 | self.cur_frame = 0; | |
256 | self.cur_pts = 0; | |
257 | self.reset_state(); | |
258 | return Ok(()); | |
259 | } | |
260 | Err(DemuxerError::NotImplemented) | |
261 | } | |
262 | } | |
263 | ||
787b8d03 KS |
264 | impl<'a> NAOptionHandler for SmackerVideoDemuxer<'a> { |
265 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
266 | fn set_options(&mut self, _options: &[NAOption]) { } | |
267 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
268 | } | |
269 | ||
606c448e KS |
270 | impl<'a> SmackerVideoDemuxer<'a> { |
271 | fn new(io: &'a mut ByteReader<'a>) -> Self { | |
272 | SmackerVideoDemuxer { | |
273 | src: io, | |
274 | frames: 0, | |
275 | pts_inc: 0, | |
276 | cur_pts: 0, | |
277 | ainfo: [AudioTrack::new(); NUM_AUDIO_TRACKS], | |
278 | frame_sizes: Vec::new(), | |
279 | frame_flags: Vec::new(), | |
280 | video_id: 0, | |
281 | start: 0, | |
282 | cur_frame: 0, | |
283 | queued_packets: Vec::new(), | |
284 | pal: [0; PAL_SIZE], | |
285 | } | |
286 | } | |
287 | fn reset_state(&mut self) { | |
288 | self.queued_packets.truncate(0); | |
289 | } | |
290 | } | |
291 | ||
292 | pub struct SMKDemuxerCreator { } | |
293 | ||
294 | impl DemuxerCreator for SMKDemuxerCreator { | |
6011e201 | 295 | fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> { |
606c448e KS |
296 | Box::new(SmackerVideoDemuxer::new(br)) |
297 | } | |
298 | fn get_name(&self) -> &'static str { "smacker" } | |
299 | } | |
300 | ||
301 | #[cfg(test)] | |
302 | mod test { | |
303 | use super::*; | |
304 | use std::fs::File; | |
305 | ||
306 | #[test] | |
307 | fn test_smk_demux() { | |
308 | let mut file = File::open("assets/RAD/20130507_audio-distortion.smk").unwrap(); | |
309 | // let mut file = File::open("assets/RAD/ajfstr1.smk").unwrap(); | |
310 | // let mut file = File::open("assets/RAD/credits.smk").unwrap(); | |
311 | // let mut file = File::open("assets/RAD/wetlogo.smk").unwrap(); | |
312 | let mut fr = FileReader::new_read(&mut file); | |
313 | let mut br = ByteReader::new(&mut fr); | |
314 | let mut dmx = SmackerVideoDemuxer::new(&mut br); | |
315 | let mut sm = StreamManager::new(); | |
caf0f37e KS |
316 | let mut si = SeekIndex::new(); |
317 | dmx.open(&mut sm, &mut si).unwrap(); | |
606c448e KS |
318 | loop { |
319 | let pktres = dmx.get_frame(&mut sm); | |
320 | if let Err(e) = pktres { | |
321 | if (e as i32) == (DemuxerError::EOF as i32) { break; } | |
322 | panic!("error"); | |
323 | } | |
324 | let pkt = pktres.unwrap(); | |
325 | println!("Got {}", pkt); | |
326 | } | |
327 | } | |
328 | } |