]>
Commit | Line | Data |
---|---|---|
9dc1fb4b KS |
1 | use nihav_core::frame::*; |
2 | use nihav_core::muxers::*; | |
3 | use super::RMStreamWriter; | |
4 | ||
5 | // fourcc, codec name, interleaver, version | |
6 | static AUDIO_CODEC_REGISTRY: &[(&[u8;4], &str, &[u8;4], u8)] = &[ | |
7 | (b"lpcJ", "ra14.4", b"Int0", 3), | |
8 | (b"28_8", "ra28.8", b"Int4", 4), | |
9 | (b"cook", "cook", b"genr", 5), | |
10 | (b"dnet", "ac3", b"Int0", 4), | |
11 | (b"sipr", "sipro", b"sipr", 4), | |
12 | (b"atrc", "atrac3", b"genr", 5), | |
13 | (b"LSD:", "ralf", b"Int0", 6), | |
14 | (b"raac", "aac", b"vbrs", 5), | |
15 | (b"racp", "aac", b"vbrf", 5), | |
16 | ]; | |
17 | ||
18 | struct InterleaveParams { | |
f62e2ae0 KS |
19 | sample_rate: u32, |
20 | channels: u8, | |
9dc1fb4b KS |
21 | block_size: usize, |
22 | factor: usize, | |
23 | frames_per_blk: usize, | |
24 | } | |
25 | ||
26 | trait Interleaver { | |
27 | fn get_flavor(&self) -> usize; | |
28 | fn get_block_size(&self) -> usize; | |
29 | fn get_factor(&self) -> usize; | |
30 | fn get_frames_per_block(&self) -> usize; | |
c5963b17 | 31 | fn is_empty(&self) -> bool; |
9dc1fb4b KS |
32 | fn add_packet(&mut self, src: &[u8]) -> bool; |
33 | fn get_packet(&mut self) -> Option<(Vec<u8>, bool)>; | |
34 | fn flush(&mut self); | |
35 | ||
36 | fn get_frame_size(&self) -> usize { self.get_block_size() / self.get_frames_per_block() } | |
37 | } | |
38 | ||
39 | struct NoInterleaver { | |
40 | frame_size: usize, | |
41 | pkt: Option<Vec<u8>>, | |
42 | } | |
43 | impl Interleaver for NoInterleaver { | |
44 | fn get_flavor(&self) -> usize { 0 } | |
45 | fn get_block_size(&self) -> usize { self.frame_size } | |
46 | fn get_factor(&self) -> usize { 1 } | |
47 | fn get_frames_per_block(&self) -> usize { 1 } | |
c5963b17 | 48 | fn is_empty(&self) -> bool { self.pkt.is_none() } |
9dc1fb4b KS |
49 | fn add_packet(&mut self, src: &[u8]) -> bool { |
50 | if self.pkt.is_none() { | |
51 | self.pkt = Some(src.to_vec()); | |
52 | true | |
53 | } else { | |
54 | false | |
55 | } | |
56 | } | |
57 | fn get_packet(&mut self) -> Option<(Vec<u8>, bool)> { | |
58 | let mut ret = None; | |
59 | std::mem::swap(&mut self.pkt, &mut ret); | |
60 | if let Some(pkt) = ret { | |
61 | Some((pkt, true)) | |
62 | } else { | |
63 | None | |
64 | } | |
65 | } | |
66 | fn flush(&mut self) {} | |
67 | } | |
68 | ||
69 | struct Int4Interleaver { | |
70 | flavor: usize, | |
71 | factor: usize, | |
72 | frame_size: usize, | |
73 | block_size: usize, | |
74 | fpb: usize, | |
75 | cur_frame: usize, | |
76 | rd_block: usize, | |
77 | buf: Vec<u8>, | |
78 | map: Vec<usize>, | |
79 | } | |
80 | impl Int4Interleaver { | |
81 | fn new(frame_size: usize) -> MuxerResult<Self> { | |
82 | let params = RA_28_8_INTERLEAVE_PARAMS; | |
83 | for (flavor, entry) in params.iter().enumerate() { | |
84 | if entry.block_size / entry.frames_per_blk == frame_size { | |
85 | let full_size = entry.frames_per_blk * entry.factor; | |
86 | let mut map = vec![0; full_size]; | |
87 | for i in 0..full_size { | |
88 | let fval = i * entry.factor; | |
89 | let mapped = (fval % full_size) + fval / full_size; | |
90 | map[mapped] = i; | |
91 | } | |
92 | ||
93 | return Ok(Self { | |
94 | flavor, | |
95 | frame_size, | |
96 | map, | |
97 | factor: entry.factor, | |
98 | block_size: entry.block_size, | |
99 | fpb: entry.frames_per_blk, | |
100 | cur_frame: 0, | |
101 | rd_block: 0, | |
102 | buf: vec![0; entry.block_size * entry.factor], | |
103 | }); | |
104 | } | |
105 | } | |
106 | Err(MuxerError::UnsupportedFormat) | |
107 | } | |
108 | } | |
109 | impl Interleaver for Int4Interleaver { | |
110 | fn get_flavor(&self) -> usize { self.flavor } | |
111 | fn get_block_size(&self) -> usize { self.block_size } | |
112 | fn get_factor(&self) -> usize { self.factor } | |
113 | fn get_frames_per_block(&self) -> usize { self.fpb } | |
c5963b17 | 114 | fn is_empty(&self) -> bool { self.cur_frame == 0 } |
9dc1fb4b KS |
115 | fn add_packet(&mut self, src: &[u8]) -> bool { |
116 | if self.cur_frame == self.factor * self.fpb { | |
117 | return false; | |
118 | } | |
119 | let pos = self.map[self.cur_frame]; | |
120 | self.buf[pos * self.frame_size..][..self.frame_size].copy_from_slice(&src); | |
121 | self.cur_frame += 1; | |
122 | true | |
123 | } | |
124 | fn get_packet(&mut self) -> Option<(Vec<u8>, bool)> { | |
125 | if self.cur_frame == self.factor * self.fpb { | |
126 | let first = self.rd_block == 0; | |
127 | let src = &self.buf[self.rd_block * self.block_size..][..self.block_size]; | |
128 | self.rd_block += 1; | |
129 | if self.rd_block == self.factor { | |
130 | self.rd_block = 0; | |
131 | self.cur_frame = 0; | |
132 | } | |
133 | Some((src.to_vec(), first)) | |
134 | } else { | |
135 | None | |
136 | } | |
137 | } | |
138 | fn flush(&mut self) { | |
139 | if self.cur_frame != 0 { | |
140 | self.cur_frame = self.factor * self.fpb; | |
141 | } | |
142 | } | |
143 | } | |
144 | ||
145 | struct GenericInterleaver { | |
146 | flavor: usize, | |
147 | factor: usize, | |
148 | frame_size: usize, | |
149 | block_size: usize, | |
150 | fpb: usize, | |
151 | cur_frame: usize, | |
152 | rd_block: usize, | |
153 | buf: Vec<u8>, | |
154 | map: Vec<usize>, | |
155 | } | |
156 | impl GenericInterleaver { | |
f62e2ae0 | 157 | fn new(ainfo: NAAudioInfo, frame_size: usize, fcc: [u8; 4]) -> MuxerResult<Self> { |
9dc1fb4b KS |
158 | let params = match &fcc { |
159 | b"atrc" => ATRAC_INTERLEAVE_PARAMS, | |
160 | b"cook" => COOK_INTERLEAVE_PARAMS, | |
161 | b"sipr" => SIPRO_INTERLEAVE_PARAMS, | |
162 | _ => return Err(MuxerError::UnsupportedFormat), | |
163 | }; | |
164 | for (flavor, entry) in params.iter().enumerate() { | |
f62e2ae0 KS |
165 | if entry.sample_rate != 0 && entry.sample_rate != ainfo.sample_rate { |
166 | continue; | |
167 | } | |
168 | if entry.channels != 0 && entry.channels != ainfo.channels { | |
169 | continue; | |
170 | } | |
9dc1fb4b KS |
171 | if entry.block_size / entry.frames_per_blk == frame_size { |
172 | let full_size = entry.frames_per_blk * entry.factor; | |
173 | let mut map = vec![0; full_size]; | |
174 | ||
175 | let mut frm = 0; | |
176 | let mut blk = 0; | |
177 | let mut even = true; | |
178 | for dst in map.iter_mut() { | |
179 | let mapped = blk * entry.frames_per_blk + frm; | |
180 | blk += 2; | |
181 | if blk >= entry.factor { | |
182 | if even { | |
183 | blk = 1; | |
184 | } else { | |
185 | blk = 0; | |
186 | frm += 1; | |
187 | } | |
188 | even = !even; | |
189 | } | |
190 | *dst = mapped; | |
191 | } | |
192 | ||
193 | return Ok(Self { | |
194 | flavor, | |
195 | frame_size, | |
196 | map, | |
197 | factor: entry.factor, | |
198 | block_size: entry.block_size, | |
199 | fpb: entry.frames_per_blk, | |
200 | cur_frame: 0, | |
201 | rd_block: 0, | |
202 | buf: vec![0; entry.block_size * entry.factor], | |
203 | }); | |
204 | } | |
205 | } | |
206 | Err(MuxerError::UnsupportedFormat) | |
207 | } | |
208 | } | |
209 | impl Interleaver for GenericInterleaver { | |
210 | fn get_flavor(&self) -> usize { self.flavor } | |
211 | fn get_block_size(&self) -> usize { self.block_size } | |
212 | fn get_factor(&self) -> usize { self.factor } | |
213 | fn get_frames_per_block(&self) -> usize { self.fpb } | |
c5963b17 | 214 | fn is_empty(&self) -> bool { self.cur_frame == 0 } |
9dc1fb4b KS |
215 | fn add_packet(&mut self, src: &[u8]) -> bool { |
216 | if self.cur_frame == self.factor * self.fpb { | |
217 | return false; | |
218 | } | |
219 | let pos = self.map[self.cur_frame]; | |
220 | self.buf[pos * self.frame_size..][..self.frame_size].copy_from_slice(&src); | |
221 | self.cur_frame += 1; | |
222 | true | |
223 | } | |
224 | fn get_packet(&mut self) -> Option<(Vec<u8>, bool)> { | |
225 | if self.cur_frame == self.factor * self.fpb { | |
226 | let first = self.rd_block == 0; | |
227 | let src = &self.buf[self.rd_block * self.block_size..][..self.block_size]; | |
228 | self.rd_block += 1; | |
229 | if self.rd_block == self.factor { | |
230 | self.rd_block = 0; | |
231 | self.cur_frame = 0; | |
232 | } | |
233 | Some((src.to_vec(), first)) | |
234 | } else { | |
235 | None | |
236 | } | |
237 | } | |
238 | fn flush(&mut self) { | |
239 | if self.cur_frame != 0 { | |
240 | self.cur_frame = self.factor * self.fpb; | |
241 | } | |
242 | } | |
243 | } | |
244 | ||
245 | struct SiproInterleaver { | |
246 | block_size: usize, | |
247 | factor: usize, | |
248 | flavor: usize, | |
249 | buf: Vec<u8>, | |
250 | wr_pos: usize, | |
251 | rd_pos: usize, | |
252 | } | |
253 | impl SiproInterleaver { | |
254 | fn new(mut frame_size: usize) -> MuxerResult<Self> { | |
255 | if frame_size == 0 { | |
256 | return Err(MuxerError::UnsupportedFormat); | |
257 | } | |
258 | while frame_size < 200 { | |
259 | frame_size <<= 1; | |
260 | } | |
261 | for (flavor, entry) in SIPRO_INTERLEAVE_PARAMS.iter().enumerate() { | |
262 | if entry.block_size == frame_size { | |
263 | return Ok(Self { | |
264 | block_size: entry.block_size, | |
265 | factor: entry.factor, | |
266 | flavor, | |
267 | buf: vec![0; entry.block_size * entry.factor], | |
268 | wr_pos: 0, | |
269 | rd_pos: 0, | |
270 | }); | |
271 | } | |
272 | } | |
273 | Err(MuxerError::UnsupportedFormat) | |
274 | } | |
275 | } | |
276 | impl Interleaver for SiproInterleaver { | |
277 | fn get_flavor(&self) -> usize { self.flavor } | |
278 | fn get_block_size(&self) -> usize { self.block_size } | |
279 | fn get_factor(&self) -> usize { self.factor } | |
280 | fn get_frames_per_block(&self) -> usize { 1 } | |
c5963b17 | 281 | fn is_empty(&self) -> bool { self.wr_pos == 0 } |
9dc1fb4b KS |
282 | fn add_packet(&mut self, src: &[u8]) -> bool { |
283 | if self.wr_pos < self.factor { | |
284 | self.buf[self.wr_pos * self.block_size..][..self.block_size].copy_from_slice(src); | |
285 | self.wr_pos += 1; | |
286 | true | |
287 | } else { | |
288 | false | |
289 | } | |
290 | } | |
291 | fn get_packet(&mut self) -> Option<(Vec<u8>, bool)> { | |
292 | if self.wr_pos == self.factor { | |
293 | let first = self.rd_pos == 0; | |
294 | if self.rd_pos == 0 { | |
295 | sipro_scramble(&mut self.buf, self.factor, self.block_size); | |
296 | } | |
297 | let ret = self.buf[self.rd_pos * self.block_size..][..self.block_size].to_vec(); | |
298 | self.rd_pos += 1; | |
299 | if self.rd_pos == self.factor { | |
300 | self.rd_pos = 0; | |
301 | self.wr_pos = 0; | |
302 | } | |
303 | Some((ret, first)) | |
304 | } else { | |
305 | None | |
306 | } | |
307 | } | |
308 | fn flush(&mut self) { | |
309 | if self.wr_pos != self.factor { | |
310 | self.wr_pos = self.factor; | |
311 | } | |
312 | } | |
313 | } | |
314 | ||
315 | fn sipro_scramble(buf: &mut [u8], factor: usize, fsize: usize) { | |
316 | let stride = factor * fsize * 2 / 96; | |
317 | for &swap_pair in SIPRO_SWAPS.iter() { | |
318 | let mut sidx = usize::from(swap_pair[0]) * stride; | |
319 | let mut didx = usize::from(swap_pair[1]) * stride; | |
320 | for _ in 0..stride { | |
321 | let in0 = buf[sidx >> 1]; | |
322 | let in1 = buf[didx >> 1]; | |
323 | let nib0 = (in0 >> ((sidx & 1) * 4)) & 0xF; | |
324 | let nib1 = (in1 >> ((didx & 1) * 4)) & 0xF; | |
325 | ||
326 | buf[didx >> 1] = (nib0 << (4 * (didx & 1))) | (in1 & (0xF << (4 * (!didx & 1)))); | |
327 | buf[sidx >> 1] = (nib1 << (4 * (sidx & 1))) | (in0 & (0xF << (4 * (!sidx & 1)))); | |
328 | ||
329 | sidx += 1; | |
330 | didx += 1; | |
331 | } | |
332 | } | |
333 | } | |
334 | ||
335 | struct AACInterleaver { | |
336 | frame_size: usize, | |
337 | data: Vec<u8>, | |
338 | sizes: Vec<usize>, | |
339 | full: bool, | |
340 | } | |
341 | impl AACInterleaver { | |
342 | fn new(frame_size: usize) -> Self { | |
343 | Self { | |
344 | frame_size, | |
345 | data: Vec::with_capacity(frame_size * 3 / 2), | |
346 | sizes: Vec::with_capacity((frame_size / 128).max(8)), | |
347 | full: false, | |
348 | } | |
349 | } | |
350 | } | |
351 | impl Interleaver for AACInterleaver { | |
352 | fn get_flavor(&self) -> usize { 0 } | |
353 | fn get_block_size(&self) -> usize { self.frame_size } | |
354 | fn get_factor(&self) -> usize { 1 } | |
355 | fn get_frames_per_block(&self) -> usize { 1 } | |
c5963b17 | 356 | fn is_empty(&self) -> bool { self.data.is_empty() } |
9dc1fb4b KS |
357 | fn add_packet(&mut self, src: &[u8]) -> bool { |
358 | if !self.full { | |
359 | self.data.extend_from_slice(src); | |
360 | self.sizes.push(src.len()); | |
361 | if self.data.len() >= self.frame_size { | |
362 | self.full = true; | |
363 | } | |
364 | true | |
365 | } else { | |
366 | false | |
367 | } | |
368 | } | |
369 | fn get_packet(&mut self) -> Option<(Vec<u8>, bool)> { | |
370 | if self.full { | |
371 | let mut dst = Vec::with_capacity(self.frame_size); | |
372 | let mut gw = GrowableMemoryWriter::new_write(&mut dst); | |
373 | let mut bw = ByteWriter::new(&mut gw); | |
374 | bw.write_u16be((self.sizes.len() * 16) as u16).unwrap(); | |
375 | for &pkt_size in self.sizes.iter() { | |
376 | bw.write_u16be(pkt_size as u16).unwrap(); | |
377 | } | |
378 | bw.write_buf(&self.data).unwrap(); | |
379 | ||
380 | self.data.clear(); | |
381 | self.sizes.clear(); | |
382 | self.full = false; | |
383 | ||
384 | Some((dst, true)) | |
385 | } else { | |
386 | None | |
387 | } | |
388 | } | |
389 | fn flush(&mut self) { | |
390 | if !self.sizes.is_empty() { | |
391 | self.full = true; | |
392 | } | |
393 | } | |
394 | } | |
395 | ||
396 | struct InterleaveInfo { | |
397 | fcc: [u8; 4], | |
398 | il_fcc: [u8; 4], | |
399 | block_size: usize, | |
400 | frame_size: usize, | |
401 | factor: usize, | |
402 | flavor: usize, | |
403 | } | |
404 | ||
405 | struct AudioStreamWriter { | |
406 | fcc: [u8; 4], | |
407 | il_fcc: [u8; 4], | |
408 | is_raw: bool, | |
409 | version: u8, | |
410 | header_pos: u64, | |
411 | interleave: Box<dyn Interleaver>, | |
412 | data_size: usize, | |
c5963b17 KS |
413 | first_time: u32, |
414 | last_time: u32, | |
415 | size_in: usize, | |
416 | size_out: usize, | |
9dc1fb4b KS |
417 | } |
418 | ||
419 | impl RMStreamWriter for AudioStreamWriter { | |
420 | fn write_header(&mut self, bw: &mut ByteWriter, astream: &NAStream) -> MuxerResult<()> { | |
421 | self.header_pos = bw.tell(); | |
422 | if self.version < 6 { | |
423 | bw.write_buf(b".ra\xFD")?; | |
424 | bw.write_u16be(self.version.into())?; | |
425 | } | |
426 | ||
427 | let il_info = InterleaveInfo { | |
428 | fcc: self.fcc, | |
429 | il_fcc: self.il_fcc, | |
430 | block_size: self.interleave.get_block_size(), | |
431 | frame_size: self.interleave.get_frame_size(), | |
432 | factor: self.interleave.get_factor(), | |
433 | flavor: self.interleave.get_flavor(), | |
434 | }; | |
435 | ||
436 | match self.version { | |
437 | 3 => write_aformat3(bw, astream, &il_info)?, | |
438 | 4 => write_aformat4(bw, astream, &il_info)?, | |
439 | 5 => write_aformat5(bw, astream, &il_info)?, | |
440 | 6 => write_lsd(bw, astream)?, | |
441 | _ => unreachable!(), | |
442 | } | |
443 | Ok(()) | |
444 | } | |
c5963b17 | 445 | fn queue_packet(&mut self, pkt: NAPacket, ms: u32) -> bool { |
9dc1fb4b KS |
446 | let src = pkt.get_buffer(); |
447 | self.data_size += src.len(); | |
448 | let frame_size = self.interleave.get_frame_size(); | |
c5963b17 KS |
449 | self.last_time = ms; |
450 | if self.interleave.is_empty() { | |
451 | self.first_time = ms; | |
452 | self.size_in = 0; | |
453 | self.size_out = 0; | |
454 | } else { | |
455 | self.size_in += src.len() / frame_size; | |
456 | } | |
9dc1fb4b KS |
457 | if !self.is_raw { |
458 | let mut ret = false; | |
459 | for frame in src.chunks(frame_size) { | |
460 | ret = self.interleave.add_packet(frame); | |
461 | } | |
462 | ret | |
463 | } else { | |
464 | self.interleave.add_packet(&src) | |
465 | } | |
466 | } | |
c5963b17 KS |
467 | fn get_packet(&mut self) -> Option<(Vec<u8>, u32, bool)> { |
468 | if let Some((pkt, first)) = self.interleave.get_packet() { | |
469 | let time_add = if self.last_time > self.first_time && self.size_in > 0 { | |
470 | let size = pkt.len(); | |
471 | let time_add = (self.size_out * ((self.last_time - self.first_time) as usize) / self.size_in) as u32; | |
472 | self.size_out += size / self.interleave.get_frame_size(); | |
473 | time_add | |
474 | } else { | |
475 | 0 | |
476 | }; | |
477 | Some((pkt, self.first_time + time_add, first)) | |
478 | } else { | |
479 | None | |
480 | } | |
481 | } | |
9dc1fb4b KS |
482 | fn flush(&mut self) { self.interleave.flush() } |
483 | fn finish(&mut self, bw: &mut ByteWriter) -> MuxerResult<()> { | |
484 | let cur_pos = bw.tell(); | |
485 | match self.version { | |
486 | 3 => { | |
487 | bw.seek(SeekFrom::Start(self.header_pos + 18))?; | |
488 | bw.write_u32be(self.data_size as u32)?; | |
489 | }, | |
490 | 4 | 5 => { | |
491 | bw.seek(SeekFrom::Start(self.header_pos + 12))?; | |
492 | bw.write_u32be(self.data_size/*+header_size*/ as u32)?; | |
493 | bw.seek(SeekFrom::Current(12))?; | |
494 | bw.write_u32be(self.data_size as u32)?; | |
495 | }, | |
496 | 6 => unimplemented!(), | |
497 | _ => unreachable!(), | |
498 | }; | |
499 | bw.seek(SeekFrom::Start(cur_pos))?; | |
500 | Ok(()) | |
501 | } | |
502 | } | |
503 | ||
504 | fn write_audio_metadata(bw: &mut ByteWriter) -> MuxerResult<()> { | |
505 | bw.write_byte(0)?; // title_string_length | |
506 | bw.write_byte(0)?; // author_string_length | |
507 | bw.write_byte(0)?; // copyright_string_length | |
508 | bw.write_byte(0)?; // user_string_length | |
509 | Ok(()) | |
510 | } | |
511 | ||
512 | fn write_aformat3(bw: &mut ByteWriter, _stream: &NAStream, il_info: &InterleaveInfo) -> MuxerResult<()> { | |
513 | let start = bw.tell(); | |
514 | bw.write_u16be(0)?; // header_bytes | |
515 | bw.write_u16be(il_info.flavor as u16)?; | |
516 | bw.write_u32be(il_info.frame_size as u32)?; // granularity | |
517 | bw.write_u32be(0)?; // bytes per minute | |
518 | bw.write_u32be(0)?; // total bytes | |
519 | write_audio_metadata(bw)?; | |
520 | bw.write_byte(0)?; //can_copy | |
521 | bw.write_byte(4)?; // FCC length | |
522 | bw.write_buf(&il_info.fcc)?; | |
523 | let end = bw.tell(); | |
524 | bw.seek(SeekFrom::Start(start))?; | |
525 | bw.write_u16be((end - start - 2) as u16)?; | |
526 | bw.seek(SeekFrom::Start(end))?; | |
527 | ||
528 | Ok(()) | |
529 | } | |
530 | ||
531 | fn write_aformat4(bw: &mut ByteWriter, stream: &NAStream, il_info: &InterleaveInfo) -> MuxerResult<()> { | |
532 | let info = stream.get_info().get_properties().get_audio_info().unwrap(); | |
533 | ||
534 | bw.write_u16be(0)?; | |
535 | let start = bw.tell(); | |
536 | bw.write_buf(b".ra4")?; | |
537 | bw.write_u32be(0)?; // data size | |
538 | bw.write_u16be(4)?; // version | |
539 | bw.write_u16be(0)?; // revision | |
540 | bw.write_u16be(0)?; // header_bytes | |
541 | bw.write_u16be(il_info.flavor as u16)?; | |
542 | bw.write_u32be(il_info.frame_size as u32)?; // granularity | |
543 | bw.write_u32be(0)?; // total bytes | |
544 | bw.write_u32be(0)?; // bytes_per_minute | |
545 | bw.write_u32be(0)?; // bytes_per_minute2 | |
546 | bw.write_u16be(il_info.factor as u16)?; | |
547 | bw.write_u16be(il_info.block_size as u16)?; | |
548 | bw.write_u16be(0)?; // user data | |
549 | bw.write_u32be(info.sample_rate)?; // sample rate | |
550 | bw.write_u32be(info.format.bits.into())?; // sample size | |
551 | bw.write_u16be(info.channels.into())?; // num channels | |
552 | bw.write_byte(4)?; // ileave ID len | |
553 | bw.write_buf(&il_info.il_fcc)?; | |
554 | bw.write_byte(4)?; // codec ID len | |
555 | bw.write_buf(&il_info.fcc)?; | |
556 | bw.write_byte(if &il_info.il_fcc == b"Int0" { 0 } else { 1 })?; | |
557 | bw.write_byte(7)?; // can_copy | |
558 | bw.write_byte(0)?; // stream_type | |
559 | write_audio_metadata(bw)?; | |
560 | let end = bw.tell(); | |
561 | bw.seek(SeekFrom::Start(start + 12))?; | |
562 | bw.write_u16be((end - start - 4) as u16)?; | |
563 | bw.seek(SeekFrom::Start(end))?; | |
564 | ||
565 | Ok(()) | |
566 | } | |
567 | ||
568 | fn write_aformat5(bw: &mut ByteWriter, stream: &NAStream, il_info: &InterleaveInfo) -> MuxerResult<()> { | |
569 | let info = stream.get_info().get_properties().get_audio_info().unwrap(); | |
570 | ||
571 | bw.write_u16be(0)?; | |
572 | let start = bw.tell(); | |
573 | bw.write_buf(b".ra5")?; | |
574 | bw.write_u32be(0)?; // data size | |
575 | bw.write_u16be(5)?; // version | |
576 | bw.write_u16be(0)?; // revision | |
577 | bw.write_u16be(0)?; // header_bytes | |
578 | bw.write_u16be(il_info.flavor as u16)?; | |
579 | bw.write_u32be(il_info.block_size as u32)?; // granularity | |
580 | bw.write_u32be(0)?; // total bytes | |
581 | bw.write_u32be(0)?; // bytes_per_minute | |
582 | bw.write_u32be(0)?; // bytes_per_minute2 | |
583 | bw.write_u16be(il_info.factor as u16)?; | |
584 | bw.write_u16be(il_info.block_size as u16)?; | |
585 | bw.write_u16be(il_info.frame_size as u16)?; | |
586 | bw.write_u16be(0)?; // user data | |
587 | bw.write_u32be(info.sample_rate)?; // sample rate | |
588 | bw.write_u32be(info.sample_rate)?; // actual sample rate | |
589 | bw.write_u32be(info.format.bits.into())?; // sample size | |
590 | bw.write_u16be(info.channels.into())?; // num channels | |
591 | bw.write_buf(&il_info.il_fcc)?; | |
592 | bw.write_buf(&il_info.fcc)?; | |
593 | bw.write_byte(if &il_info.il_fcc == b"Int0" { 0 } else { 1 })?; | |
594 | bw.write_byte(7)?; // can_copy | |
595 | bw.write_byte(0)?; // stream_type | |
596 | bw.write_byte(0)?; // has_interleave_pattern | |
597 | if let Some(edata) = stream.get_info().get_extradata() { | |
598 | if !matches!(&il_info.fcc, b"raac" | b"racp") { | |
599 | bw.write_u32be(edata.len() as u32)?; | |
600 | bw.write_buf(&edata)?; | |
601 | } else { | |
602 | bw.write_u32be((edata.len() + 1) as u32)?; | |
603 | bw.write_byte(2)?; | |
604 | bw.write_buf(&edata)?; | |
605 | } | |
606 | } else { | |
607 | bw.write_u32be(0)?; | |
608 | } | |
609 | let end = bw.tell(); | |
610 | bw.seek(SeekFrom::Start(start + 12))?; | |
611 | bw.write_u16be((end - start - 4) as u16)?; | |
612 | bw.seek(SeekFrom::Start(end))?; | |
613 | ||
614 | Ok(()) | |
615 | } | |
616 | ||
617 | fn write_lsd(bw: &mut ByteWriter, stream: &NAStream) -> MuxerResult<()> { | |
618 | if let Some(edata) = stream.get_info().get_extradata() { | |
619 | bw.write_buf(&edata)?; | |
620 | } | |
621 | Ok(()) | |
622 | } | |
623 | ||
624 | fn create_interleaver(id: [u8; 4], fcc: [u8; 4], ainfo: NAAudioInfo) -> MuxerResult<Box<dyn Interleaver>> { | |
625 | let frame_size = ainfo.block_len; | |
626 | match &id { | |
627 | b"Int0" => Ok(Box::new(NoInterleaver{ frame_size, pkt: None })), | |
628 | b"Int4" => Ok(Box::new(Int4Interleaver::new(frame_size)?)), | |
629 | b"sipr" => Ok(Box::new(SiproInterleaver::new(frame_size)?)), | |
f62e2ae0 | 630 | b"genr" => Ok(Box::new(GenericInterleaver::new(ainfo, frame_size, fcc)?)), |
9dc1fb4b KS |
631 | b"vbrs" | b"vbrf" => Ok(Box::new(AACInterleaver::new(1024))), |
632 | _ => unimplemented!(), | |
633 | } | |
634 | } | |
635 | ||
636 | pub fn create_audio_stream(stream: &NAStream) -> MuxerResult<Box<dyn RMStreamWriter>> { | |
637 | let info = stream.get_info(); | |
638 | let cname = info.get_name(); | |
639 | let mut fourcc = [0u8; 4]; | |
640 | let mut ileave = [0u8; 4]; | |
641 | let mut version = 0; | |
642 | for &(fcc, name, ileaver, cversion) in AUDIO_CODEC_REGISTRY.iter() { | |
643 | if name == cname { | |
644 | fourcc = *fcc; | |
645 | ileave = *ileaver; | |
646 | version = cversion; | |
647 | break; | |
648 | } | |
649 | } | |
650 | if version > 0 { | |
651 | let ainfo = info.get_properties().get_audio_info().unwrap(); | |
652 | Ok(Box::new(AudioStreamWriter { | |
653 | fcc: fourcc, | |
654 | il_fcc: ileave, | |
655 | is_raw: &ileave == b"Int0", | |
656 | version, | |
657 | interleave: create_interleaver(ileave, fourcc, ainfo)?, | |
658 | header_pos: 0, | |
659 | data_size: 0, | |
c5963b17 KS |
660 | first_time: 0, |
661 | last_time: 0, | |
662 | size_in: 0, | |
663 | size_out: 0, | |
9dc1fb4b KS |
664 | })) |
665 | } else { | |
666 | Err(MuxerError::UnsupportedFormat) | |
667 | } | |
668 | } | |
669 | ||
670 | const SIPRO_SWAPS: [[u8; 2]; 38] = [ | |
671 | [ 0, 63 ], [ 1, 22 ], [ 2, 44 ], [ 3, 90 ], | |
672 | [ 5, 81 ], [ 7, 31 ], [ 8, 86 ], [ 9, 58 ], | |
673 | [ 10, 36 ], [ 12, 68 ], [ 13, 39 ], [ 14, 73 ], | |
674 | [ 15, 53 ], [ 16, 69 ], [ 17, 57 ], [ 19, 88 ], | |
675 | [ 20, 34 ], [ 21, 71 ], [ 24, 46 ], [ 25, 94 ], | |
676 | [ 26, 54 ], [ 28, 75 ], [ 29, 50 ], [ 32, 70 ], | |
677 | [ 33, 92 ], [ 35, 74 ], [ 38, 85 ], [ 40, 56 ], | |
678 | [ 42, 87 ], [ 43, 65 ], [ 45, 59 ], [ 48, 79 ], | |
679 | [ 49, 93 ], [ 51, 89 ], [ 55, 95 ], [ 61, 76 ], | |
680 | [ 67, 83 ], [ 77, 80 ] | |
681 | ]; | |
682 | ||
f62e2ae0 KS |
683 | macro_rules! int_params { |
684 | ($rate:expr, $ch:expr, $bsize:expr, $factor:expr, $frm_per_blk:expr) => { | |
685 | InterleaveParams { | |
686 | sample_rate: $rate, | |
687 | channels: $ch, | |
688 | block_size: $bsize, | |
689 | factor: $factor, | |
690 | frames_per_blk: $frm_per_blk, | |
691 | } | |
692 | } | |
693 | } | |
694 | ||
9dc1fb4b | 695 | const RA_28_8_INTERLEAVE_PARAMS: &[InterleaveParams] = &[ |
f62e2ae0 | 696 | int_params!(0, 1, 228, 12, 6) |
9dc1fb4b | 697 | ]; |
f62e2ae0 KS |
698 | const SIPRO_INTERLEAVE_PARAMS: &[InterleaveParams] = &[ //2,1,3,0 |
699 | int_params!( 8000, 1, 232, 6, 16), | |
700 | int_params!( 8000, 1, 304, 6, 16), | |
701 | int_params!( 8000, 1, 296, 6, 16), | |
702 | int_params!(16000, 1, 320, 6, 16), | |
9dc1fb4b KS |
703 | ]; |
704 | const ATRAC_INTERLEAVE_PARAMS: &[InterleaveParams] = &[ | |
f62e2ae0 KS |
705 | int_params!(0, 0, 768, 20, 4), |
706 | int_params!(0, 0, 1088, 20, 4), | |
707 | int_params!(0, 0, 912, 30, 3), | |
708 | int_params!(0, 0, 1152, 30, 3), | |
709 | int_params!(0, 0, 1272, 30, 3), | |
710 | int_params!(0, 0, 1024, 30, 2), | |
711 | int_params!(0, 0, 768, 10, 1), | |
712 | int_params!(0, 0, 1024, 10, 1), | |
9dc1fb4b KS |
713 | ]; |
714 | const COOK_INTERLEAVE_PARAMS: &[InterleaveParams] = &[ | |
f62e2ae0 KS |
715 | int_params!( 8000, 1, 288, 8, 9), |
716 | int_params!(11025, 1, 352, 8, 11), | |
717 | int_params!(22050, 1, 564, 8, 12), | |
718 | int_params!(22050, 1, 600, 9, 10), | |
719 | int_params!(44100, 1, 651, 14, 7), | |
720 | int_params!(44100, 1, 640, 15, 5), | |
721 | int_params!(44100, 1, 744, 20, 4), | |
722 | int_params!(22050, 1, 558, 16, 6), | |
723 | int_params!( 8000, 1, 288, 6, 12), | |
724 | int_params!(11025, 2, 580, 10, 10), | |
725 | int_params!(22050, 2, 564, 14, 6), | |
726 | int_params!(22050, 2, 640, 16, 5), | |
727 | int_params!(44100, 2, 744, 20, 4), | |
728 | int_params!(44100, 2, 834, 30, 3), | |
729 | int_params!(44100, 1, 644, 20, 4), | |
730 | int_params!(44100, 1, 600, 9, 10), | |
731 | int_params!(44100, 1, 651, 14, 7), | |
732 | int_params!(22050, 2, 528, 10, 10), | |
733 | int_params!(22050, 2, 600, 10, 10), | |
734 | int_params!(22050, 2, 600, 10, 10), | |
735 | int_params!(22050, 2, 465, 16, 5), | |
736 | int_params!(44100, 2, 465, 16, 5), | |
737 | int_params!(44100, 2, 640, 16, 5), | |
738 | int_params!(44100, 2, 640, 16, 5), | |
739 | int_params!(44100, 2, 930, 16, 5), | |
740 | int_params!(44100, 2, 1400, 16, 5), | |
741 | int_params!(11025, 2, 376, 8, 11), | |
742 | int_params!(44100, 2, 930, 16, 5), | |
743 | int_params!(44100, 2, 1400, 16, 5), | |
744 | int_params!(22050, 2, 640, 16, 5), | |
745 | int_params!(44100, 5, 1395, 16, 5), | |
746 | int_params!(44100, 6, 1143, 10, 3), | |
747 | int_params!(44100, 6, 1064, 10, 2), | |
748 | int_params!(44100, 6, 778, 1, 1), | |
9dc1fb4b | 749 | ]; |