| 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 { |
| 19 | sample_rate: u32, |
| 20 | channels: u8, |
| 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; |
| 31 | fn is_empty(&self) -> bool; |
| 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 } |
| 48 | fn is_empty(&self) -> bool { self.pkt.is_none() } |
| 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 } |
| 114 | fn is_empty(&self) -> bool { self.cur_frame == 0 } |
| 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 { |
| 157 | fn new(ainfo: NAAudioInfo, frame_size: usize, fcc: [u8; 4]) -> MuxerResult<Self> { |
| 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() { |
| 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 | } |
| 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 } |
| 214 | fn is_empty(&self) -> bool { self.cur_frame == 0 } |
| 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 } |
| 281 | fn is_empty(&self) -> bool { self.wr_pos == 0 } |
| 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 } |
| 356 | fn is_empty(&self) -> bool { self.data.is_empty() } |
| 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, |
| 413 | first_time: u32, |
| 414 | last_time: u32, |
| 415 | size_in: usize, |
| 416 | size_out: usize, |
| 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 | } |
| 445 | fn queue_packet(&mut self, pkt: NAPacket, ms: u32) -> bool { |
| 446 | let src = pkt.get_buffer(); |
| 447 | self.data_size += src.len(); |
| 448 | let frame_size = self.interleave.get_frame_size(); |
| 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 | } |
| 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 | } |
| 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 | } |
| 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 | fn set_pkt_size(&mut self, _pkt_size: usize) {} |
| 503 | } |
| 504 | |
| 505 | fn write_audio_metadata(bw: &mut ByteWriter) -> MuxerResult<()> { |
| 506 | bw.write_byte(0)?; // title_string_length |
| 507 | bw.write_byte(0)?; // author_string_length |
| 508 | bw.write_byte(0)?; // copyright_string_length |
| 509 | bw.write_byte(0)?; // user_string_length |
| 510 | Ok(()) |
| 511 | } |
| 512 | |
| 513 | fn write_aformat3(bw: &mut ByteWriter, _stream: &NAStream, il_info: &InterleaveInfo) -> MuxerResult<()> { |
| 514 | let start = bw.tell(); |
| 515 | bw.write_u16be(0)?; // header_bytes |
| 516 | bw.write_u16be(il_info.flavor as u16)?; |
| 517 | bw.write_u32be(il_info.frame_size as u32)?; // granularity |
| 518 | bw.write_u32be(0)?; // bytes per minute |
| 519 | bw.write_u32be(0)?; // total bytes |
| 520 | write_audio_metadata(bw)?; |
| 521 | bw.write_byte(0)?; //can_copy |
| 522 | bw.write_byte(4)?; // FCC length |
| 523 | bw.write_buf(&il_info.fcc)?; |
| 524 | let end = bw.tell(); |
| 525 | bw.seek(SeekFrom::Start(start))?; |
| 526 | bw.write_u16be((end - start - 2) as u16)?; |
| 527 | bw.seek(SeekFrom::Start(end))?; |
| 528 | |
| 529 | Ok(()) |
| 530 | } |
| 531 | |
| 532 | fn write_aformat4(bw: &mut ByteWriter, stream: &NAStream, il_info: &InterleaveInfo) -> MuxerResult<()> { |
| 533 | let info = stream.get_info().get_properties().get_audio_info().unwrap(); |
| 534 | |
| 535 | bw.write_u16be(0)?; |
| 536 | let start = bw.tell(); |
| 537 | bw.write_buf(b".ra4")?; |
| 538 | bw.write_u32be(0)?; // data size |
| 539 | bw.write_u16be(4)?; // version |
| 540 | bw.write_u16be(0)?; // revision |
| 541 | bw.write_u16be(0)?; // header_bytes |
| 542 | bw.write_u16be(il_info.flavor as u16)?; |
| 543 | bw.write_u32be(il_info.frame_size as u32)?; // granularity |
| 544 | bw.write_u32be(0)?; // total bytes |
| 545 | bw.write_u32be(0)?; // bytes_per_minute |
| 546 | bw.write_u32be(0)?; // bytes_per_minute2 |
| 547 | bw.write_u16be(il_info.factor as u16)?; |
| 548 | bw.write_u16be(il_info.block_size as u16)?; |
| 549 | bw.write_u16be(0)?; // user data |
| 550 | bw.write_u32be(info.sample_rate)?; // sample rate |
| 551 | bw.write_u32be(info.format.bits.into())?; // sample size |
| 552 | bw.write_u16be(info.channels.into())?; // num channels |
| 553 | bw.write_byte(4)?; // ileave ID len |
| 554 | bw.write_buf(&il_info.il_fcc)?; |
| 555 | bw.write_byte(4)?; // codec ID len |
| 556 | bw.write_buf(&il_info.fcc)?; |
| 557 | bw.write_byte(if &il_info.il_fcc == b"Int0" { 0 } else { 1 })?; |
| 558 | bw.write_byte(7)?; // can_copy |
| 559 | bw.write_byte(0)?; // stream_type |
| 560 | write_audio_metadata(bw)?; |
| 561 | let end = bw.tell(); |
| 562 | bw.seek(SeekFrom::Start(start + 12))?; |
| 563 | bw.write_u16be((end - start - 4) as u16)?; |
| 564 | bw.seek(SeekFrom::Start(end))?; |
| 565 | |
| 566 | Ok(()) |
| 567 | } |
| 568 | |
| 569 | fn write_aformat5(bw: &mut ByteWriter, stream: &NAStream, il_info: &InterleaveInfo) -> MuxerResult<()> { |
| 570 | let info = stream.get_info().get_properties().get_audio_info().unwrap(); |
| 571 | |
| 572 | bw.write_u16be(0)?; |
| 573 | let start = bw.tell(); |
| 574 | bw.write_buf(b".ra5")?; |
| 575 | bw.write_u32be(0)?; // data size |
| 576 | bw.write_u16be(5)?; // version |
| 577 | bw.write_u16be(0)?; // revision |
| 578 | bw.write_u16be(0)?; // header_bytes |
| 579 | bw.write_u16be(il_info.flavor as u16)?; |
| 580 | bw.write_u32be(il_info.block_size as u32)?; // granularity |
| 581 | bw.write_u32be(0)?; // total bytes |
| 582 | bw.write_u32be(0)?; // bytes_per_minute |
| 583 | bw.write_u32be(0)?; // bytes_per_minute2 |
| 584 | bw.write_u16be(il_info.factor as u16)?; |
| 585 | bw.write_u16be(il_info.block_size as u16)?; |
| 586 | bw.write_u16be(il_info.frame_size as u16)?; |
| 587 | bw.write_u16be(0)?; // user data |
| 588 | bw.write_u32be(info.sample_rate)?; // sample rate |
| 589 | bw.write_u32be(info.sample_rate)?; // actual sample rate |
| 590 | bw.write_u32be(info.format.bits.into())?; // sample size |
| 591 | bw.write_u16be(info.channels.into())?; // num channels |
| 592 | bw.write_buf(&il_info.il_fcc)?; |
| 593 | bw.write_buf(&il_info.fcc)?; |
| 594 | bw.write_byte(if &il_info.il_fcc == b"Int0" { 0 } else { 1 })?; |
| 595 | bw.write_byte(7)?; // can_copy |
| 596 | bw.write_byte(0)?; // stream_type |
| 597 | bw.write_byte(0)?; // has_interleave_pattern |
| 598 | if let Some(edata) = stream.get_info().get_extradata() { |
| 599 | if !matches!(&il_info.fcc, b"raac" | b"racp") { |
| 600 | bw.write_u32be(edata.len() as u32)?; |
| 601 | bw.write_buf(&edata)?; |
| 602 | } else { |
| 603 | bw.write_u32be((edata.len() + 1) as u32)?; |
| 604 | bw.write_byte(2)?; |
| 605 | bw.write_buf(&edata)?; |
| 606 | } |
| 607 | } else { |
| 608 | bw.write_u32be(0)?; |
| 609 | } |
| 610 | let end = bw.tell(); |
| 611 | bw.seek(SeekFrom::Start(start + 12))?; |
| 612 | bw.write_u16be((end - start - 4) as u16)?; |
| 613 | bw.seek(SeekFrom::Start(end))?; |
| 614 | |
| 615 | Ok(()) |
| 616 | } |
| 617 | |
| 618 | fn write_lsd(bw: &mut ByteWriter, stream: &NAStream) -> MuxerResult<()> { |
| 619 | if let Some(edata) = stream.get_info().get_extradata() { |
| 620 | bw.write_buf(&edata)?; |
| 621 | } |
| 622 | Ok(()) |
| 623 | } |
| 624 | |
| 625 | fn create_interleaver(id: [u8; 4], fcc: [u8; 4], ainfo: NAAudioInfo) -> MuxerResult<Box<dyn Interleaver>> { |
| 626 | let frame_size = ainfo.block_len; |
| 627 | match &id { |
| 628 | b"Int0" => Ok(Box::new(NoInterleaver{ frame_size, pkt: None })), |
| 629 | b"Int4" => Ok(Box::new(Int4Interleaver::new(frame_size)?)), |
| 630 | b"sipr" => Ok(Box::new(SiproInterleaver::new(frame_size)?)), |
| 631 | b"genr" => Ok(Box::new(GenericInterleaver::new(ainfo, frame_size, fcc)?)), |
| 632 | b"vbrs" | b"vbrf" => Ok(Box::new(AACInterleaver::new(1024))), |
| 633 | _ => unimplemented!(), |
| 634 | } |
| 635 | } |
| 636 | |
| 637 | pub fn create_audio_stream(stream: &NAStream) -> MuxerResult<Box<dyn RMStreamWriter>> { |
| 638 | let info = stream.get_info(); |
| 639 | let cname = info.get_name(); |
| 640 | let mut fourcc = [0u8; 4]; |
| 641 | let mut ileave = [0u8; 4]; |
| 642 | let mut version = 0; |
| 643 | for &(fcc, name, ileaver, cversion) in AUDIO_CODEC_REGISTRY.iter() { |
| 644 | if name == cname { |
| 645 | fourcc = *fcc; |
| 646 | ileave = *ileaver; |
| 647 | version = cversion; |
| 648 | break; |
| 649 | } |
| 650 | } |
| 651 | if version > 0 { |
| 652 | let ainfo = info.get_properties().get_audio_info().unwrap(); |
| 653 | Ok(Box::new(AudioStreamWriter { |
| 654 | fcc: fourcc, |
| 655 | il_fcc: ileave, |
| 656 | is_raw: &ileave == b"Int0", |
| 657 | version, |
| 658 | interleave: create_interleaver(ileave, fourcc, ainfo)?, |
| 659 | header_pos: 0, |
| 660 | data_size: 0, |
| 661 | first_time: 0, |
| 662 | last_time: 0, |
| 663 | size_in: 0, |
| 664 | size_out: 0, |
| 665 | })) |
| 666 | } else { |
| 667 | Err(MuxerError::UnsupportedFormat) |
| 668 | } |
| 669 | } |
| 670 | |
| 671 | const SIPRO_SWAPS: [[u8; 2]; 38] = [ |
| 672 | [ 0, 63 ], [ 1, 22 ], [ 2, 44 ], [ 3, 90 ], |
| 673 | [ 5, 81 ], [ 7, 31 ], [ 8, 86 ], [ 9, 58 ], |
| 674 | [ 10, 36 ], [ 12, 68 ], [ 13, 39 ], [ 14, 73 ], |
| 675 | [ 15, 53 ], [ 16, 69 ], [ 17, 57 ], [ 19, 88 ], |
| 676 | [ 20, 34 ], [ 21, 71 ], [ 24, 46 ], [ 25, 94 ], |
| 677 | [ 26, 54 ], [ 28, 75 ], [ 29, 50 ], [ 32, 70 ], |
| 678 | [ 33, 92 ], [ 35, 74 ], [ 38, 85 ], [ 40, 56 ], |
| 679 | [ 42, 87 ], [ 43, 65 ], [ 45, 59 ], [ 48, 79 ], |
| 680 | [ 49, 93 ], [ 51, 89 ], [ 55, 95 ], [ 61, 76 ], |
| 681 | [ 67, 83 ], [ 77, 80 ] |
| 682 | ]; |
| 683 | |
| 684 | macro_rules! int_params { |
| 685 | ($rate:expr, $ch:expr, $bsize:expr, $factor:expr, $frm_per_blk:expr) => { |
| 686 | InterleaveParams { |
| 687 | sample_rate: $rate, |
| 688 | channels: $ch, |
| 689 | block_size: $bsize, |
| 690 | factor: $factor, |
| 691 | frames_per_blk: $frm_per_blk, |
| 692 | } |
| 693 | } |
| 694 | } |
| 695 | |
| 696 | const RA_28_8_INTERLEAVE_PARAMS: &[InterleaveParams] = &[ |
| 697 | int_params!(0, 1, 228, 12, 6) |
| 698 | ]; |
| 699 | const SIPRO_INTERLEAVE_PARAMS: &[InterleaveParams] = &[ //2,1,3,0 |
| 700 | int_params!( 8000, 1, 232, 6, 16), |
| 701 | int_params!( 8000, 1, 304, 6, 16), |
| 702 | int_params!( 8000, 1, 296, 6, 16), |
| 703 | int_params!(16000, 1, 320, 6, 16), |
| 704 | ]; |
| 705 | const ATRAC_INTERLEAVE_PARAMS: &[InterleaveParams] = &[ |
| 706 | int_params!(0, 0, 768, 20, 4), |
| 707 | int_params!(0, 0, 1088, 20, 4), |
| 708 | int_params!(0, 0, 912, 30, 3), |
| 709 | int_params!(0, 0, 1152, 30, 3), |
| 710 | int_params!(0, 0, 1272, 30, 3), |
| 711 | int_params!(0, 0, 1024, 30, 2), |
| 712 | int_params!(0, 0, 768, 10, 1), |
| 713 | int_params!(0, 0, 1024, 10, 1), |
| 714 | ]; |
| 715 | const COOK_INTERLEAVE_PARAMS: &[InterleaveParams] = &[ |
| 716 | int_params!( 8000, 1, 288, 8, 9), |
| 717 | int_params!(11025, 1, 352, 8, 11), |
| 718 | int_params!(22050, 1, 564, 8, 12), |
| 719 | int_params!(22050, 1, 600, 9, 10), |
| 720 | int_params!(44100, 1, 651, 14, 7), |
| 721 | int_params!(44100, 1, 640, 15, 5), |
| 722 | int_params!(44100, 1, 744, 20, 4), |
| 723 | int_params!(22050, 1, 558, 16, 6), |
| 724 | int_params!( 8000, 1, 288, 6, 12), |
| 725 | int_params!(11025, 2, 580, 10, 10), |
| 726 | int_params!(22050, 2, 564, 14, 6), |
| 727 | int_params!(22050, 2, 640, 16, 5), |
| 728 | int_params!(44100, 2, 744, 20, 4), |
| 729 | int_params!(44100, 2, 834, 30, 3), |
| 730 | int_params!(44100, 1, 644, 20, 4), |
| 731 | int_params!(44100, 1, 600, 9, 10), |
| 732 | int_params!(44100, 1, 651, 14, 7), |
| 733 | int_params!(22050, 2, 528, 10, 10), |
| 734 | int_params!(22050, 2, 600, 10, 10), |
| 735 | int_params!(22050, 2, 600, 10, 10), |
| 736 | int_params!(22050, 2, 465, 16, 5), |
| 737 | int_params!(44100, 2, 465, 16, 5), |
| 738 | int_params!(44100, 2, 640, 16, 5), |
| 739 | int_params!(44100, 2, 640, 16, 5), |
| 740 | int_params!(44100, 2, 930, 16, 5), |
| 741 | int_params!(44100, 2, 1400, 16, 5), |
| 742 | int_params!(11025, 2, 376, 8, 11), |
| 743 | int_params!(44100, 2, 930, 16, 5), |
| 744 | int_params!(44100, 2, 1400, 16, 5), |
| 745 | int_params!(22050, 2, 640, 16, 5), |
| 746 | int_params!(44100, 5, 1395, 16, 5), |
| 747 | int_params!(44100, 6, 1143, 10, 3), |
| 748 | int_params!(44100, 6, 1064, 10, 2), |
| 749 | int_params!(44100, 6, 778, 1, 1), |
| 750 | ]; |