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