diff --git a/Cargo.lock b/Cargo.lock index 2a0e7e7..88fbc39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,7 +25,7 @@ dependencies = [ [[package]] name = "mp4-merge" -version = "0.1.3" +version = "0.1.4" dependencies = [ "byteorder", "log", diff --git a/src/desc_reader.rs b/src/desc_reader.rs index a8ce74b..8414fbe 100644 --- a/src/desc_reader.rs +++ b/src/desc_reader.rs @@ -22,6 +22,7 @@ pub struct TrackDesc { pub stsz_count: u32, pub stsc: Vec<(u32, u32, u32)>, // first_chunk, samples_per_chunk, sample_description_index pub co64_final_position: u64, + pub skip: bool, } #[derive(Default, Clone, Debug)] @@ -33,14 +34,13 @@ pub struct Desc { pub mdat_final_position: u64, } -pub fn read_desc(d: &mut R, desc: &mut Desc, track: usize, max_read: u64) -> Result<()> { - let mut total_read_size = 0; +pub fn read_desc(d: &mut R, desc: &mut Desc, track: usize, max_read: u64, file_index: usize) -> Result<()> { let mut tl_track = track; + let start_offs = d.stream_position()?; while let Ok((typ, offs, size, header_size)) = read_box(d) { - if size == 0 || typ == 0 { break; } - total_read_size += size; - if crate::has_children(typ) { - read_desc(d, desc, tl_track, size - header_size as u64)?; + if size == 0 || typ == 0 { continue; } + if crate::has_children(typ, true) { + read_desc(d, desc, tl_track, size - header_size as u64, file_index)?; if typ == fourcc("trak") { tl_track += 1; @@ -72,44 +72,51 @@ pub fn read_desc(d: &mut R, desc: &mut Desc, track: usize, max_r if typ == fourcc("elst") || typ == fourcc("stts") || typ == fourcc("stsz") || typ == fourcc("stss") || typ == fourcc("stco") || typ == fourcc("co64") || typ == fourcc("sdtp") || typ == fourcc("stsc") { let track_desc = desc.moov_tracks.get_mut(tl_track).unwrap(); - let (v, _flags) = (d.read_u8()?, d.read_u24::()?); + if !(track_desc.skip && file_index > 0) { + let (v, _flags) = (d.read_u8()?, d.read_u24::()?); - if typ == fourcc("elst") { - d.seek(SeekFrom::Current(4))?; // Skip fields - track_desc.elst_segment_duration += if v == 1 { d.read_u64::()? } else { d.read_u32::()? as u64 }; - } - if typ == fourcc("stsz") { - track_desc.stsz_sample_size = d.read_u32::()?; - let count = d.read_u32::()?; - if track_desc.stsz_sample_size == 0 { - for _ in 0..count { track_desc.stsz.push(d.read_u32::()?); } + if typ == fourcc("elst") { + d.seek(SeekFrom::Current(4))?; // Skip fields + track_desc.elst_segment_duration += if v == 1 { d.read_u64::()? } else { d.read_u32::()? as u64 }; } - track_desc.stsz_count += count; - } - if typ == fourcc("sdtp") { - let count = size - header_size as u64 - 4; - for _ in 0..count { track_desc.sdtp.push(d.read_u8()?); } - } - if typ == fourcc("stss") || typ == fourcc("stco") || typ == fourcc("co64") || typ == fourcc("stts") || typ == fourcc("stsc") { - let count = d.read_u32::()?; - let current_file_mdat_position = desc.mdat_position.last().unwrap().1; - let mdat_offset = desc.mdat_offset as i64 - current_file_mdat_position as i64; - for _ in 0..count { - if typ == fourcc("stss") { track_desc.stss.push(d.read_u32::()? + track_desc.sample_offset); } - if typ == fourcc("stco") { track_desc.stco.push((d.read_u32::()? as i64 + mdat_offset) as u64); } - if typ == fourcc("co64") { track_desc.stco.push((d.read_u64::()? as i64 + mdat_offset) as u64); } - if typ == fourcc("stts") { track_desc.stts.push((d.read_u32::()?, d.read_u32::()?)); } - if typ == fourcc("stsc") { track_desc.stsc.push(( - d.read_u32::()? + track_desc.chunk_offset, - d.read_u32::()?, - d.read_u32::()? - )); } + if typ == fourcc("stsz") { + track_desc.stsz_sample_size = d.read_u32::()?; + let count = d.read_u32::()?; + if track_desc.stsz_sample_size == 0 { + for _ in 0..count { track_desc.stsz.push(d.read_u32::()?); } + } + track_desc.stsz_count += count; + } + if typ == fourcc("sdtp") { + let count = size - header_size as u64 - 4; + for _ in 0..count { track_desc.sdtp.push(d.read_u8()?); } + } + if typ == fourcc("stss") || typ == fourcc("stco") || typ == fourcc("co64") || typ == fourcc("stts") || typ == fourcc("stsc") { + let count = d.read_u32::()?; + let current_file_mdat_position = desc.mdat_position.last().unwrap().1; + let mdat_offset = desc.mdat_offset as i64 - current_file_mdat_position as i64; + for _ in 0..count { + if typ == fourcc("stss") { track_desc.stss.push(d.read_u32::()? + track_desc.sample_offset); } + if typ == fourcc("stco") { track_desc.stco.push((d.read_u32::()? as i64 + mdat_offset) as u64); } + if typ == fourcc("co64") { track_desc.stco.push((d.read_u64::()? as i64 + mdat_offset) as u64); } + if typ == fourcc("stts") { track_desc.stts.push((d.read_u32::()?, d.read_u32::()?)); } + if typ == fourcc("stsc") { track_desc.stsc.push(( + d.read_u32::()? + track_desc.chunk_offset, + d.read_u32::()?, + d.read_u32::()? + )); } + } } } } + if typ == fourcc("tmcd") { + // Timecode shouldn't be merged + let track_desc = desc.moov_tracks.get_mut(tl_track).unwrap(); + track_desc.skip = true; + } d.seek(SeekFrom::Start(org_pos + size - header_size as u64))?; } - if total_read_size >= max_read { + if d.stream_position()? - start_offs >= max_read { break; } } diff --git a/src/lib.rs b/src/lib.rs index 495bf2e..cb517d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,9 +27,10 @@ const fn fourcc(s: &str) -> u32 { let s = s.as_bytes(); (s[3] as u32) | ((s[2] as u32) << 8) | ((s[1] as u32) << 16) | ((s[0] as u32) << 24) } -const fn has_children(typ: u32) -> bool { +const fn has_children(typ: u32, is_read: bool) -> bool { typ == fourcc("moov") || typ == fourcc("trak") || typ == fourcc("edts") || - typ == fourcc("mdia") || typ == fourcc("minf") || typ == fourcc("stbl") + typ == fourcc("mdia") || typ == fourcc("minf") || typ == fourcc("stbl") || + (typ == fourcc("stsd") && is_read) } fn typ_to_str(typ: u32) -> String { unsafe { String::from_utf8_unchecked(vec![(typ >> 24) as u8, (typ >> 16) as u8, (typ >> 8) as u8, typ as u8 ]) } @@ -70,7 +71,7 @@ pub fn join_files + AsRef, F: Fn(f64)>(files: &[ fs.seek(std::io::SeekFrom::Start(0))?; } - desc_reader::read_desc(&mut fs, &mut desc, 0, u64::MAX)?; + desc_reader::read_desc(&mut fs, &mut desc, 0, u64::MAX, i)?; if let Some(mdat) = desc.mdat_position.last_mut() { mdat.0 = Some(PathBuf::from(path)); diff --git a/src/writer.rs b/src/writer.rs index 96ae0d9..1034a31 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -14,7 +14,7 @@ pub fn rewrite_from_desc(d: &mut R, output_file total_read_size += size; let mut new_size = size; - if crate::has_children(typ) { + if crate::has_children(typ, false) { // Copy the header d.seek(SeekFrom::Current(-header_size))?; let out_pos = output_file.stream_position()?; @@ -164,7 +164,7 @@ pub fn rewrite_from_desc(d: &mut R, output_file Ok(total_new_size) } -fn patch_bytes(writer: &mut W, position: u64, bytes: &[u8]) -> Result<()> { +pub fn patch_bytes(writer: &mut W, position: u64, bytes: &[u8]) -> Result<()> { let new_pos = writer.stream_position()?; writer.seek(SeekFrom::Start(position))?; writer.write(bytes)?;