bodge mp4 files

This commit is contained in:
2026-03-11 08:58:56 -07:00
parent 6df057de17
commit 9007de1a2d
3 changed files with 122 additions and 6 deletions

71
Cargo.lock generated
View File

@@ -873,6 +873,12 @@ dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "jni"
version = "0.21.1"
@@ -1049,6 +1055,20 @@ dependencies = [
"paste",
]
[[package]]
name = "mp4"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9ef834d5ed55e494a2ae350220314dc4aacd1c43a9498b00e320e0ea352a5c3"
dependencies = [
"byteorder",
"bytes",
"num-rational",
"serde",
"serde_json",
"thiserror 1.0.69",
]
[[package]]
name = "mp4ra-rust"
version = "0.3.0"
@@ -1120,6 +1140,37 @@ dependencies = [
"jni-sys",
]
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [
"num-bigint",
"num-integer",
"num-traits",
"serde",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -1741,6 +1792,19 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "serde_json"
version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "shlex"
version = "1.3.0"
@@ -2121,6 +2185,7 @@ version = "0.1.0"
dependencies = [
"clap",
"glam",
"mp4",
"strafesnet_common",
"strafesnet_graphics",
"strafesnet_roblox_bot_file",
@@ -2952,3 +3017,9 @@ dependencies = [
"quote",
"syn 2.0.117",
]
[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"

View File

@@ -13,3 +13,4 @@ strafesnet_roblox_bot_file.workspace = true
strafesnet_snf.workspace = true
vk-video = "0.2.0"
clap = { version = "4.5.60", features = ["derive"] }
mp4 = "0.14.0"

View File

@@ -1,4 +1,3 @@
use std::io::Write;
use std::num::NonZeroU32;
use std::path::PathBuf;
use strafesnet_common::session::Time as SessionTime;
@@ -48,7 +47,7 @@ impl EncodeSubcommand{
device:self.device,
output_file:self.output_file.unwrap_or_else(||{
let mut output_file:PathBuf=self.bot.file_stem().unwrap().into();
output_file.set_extension("h264");
output_file.set_extension("mp4");
output_file
}),
map:self.map,
@@ -73,7 +72,10 @@ enum EncodeError{
VideoCreateTextures(vk_video::VulkanEncoderError),
VideoEncodeFrame(vk_video::VulkanEncoderError),
OutputCreateFile(std::io::Error),
OutputWriteFile(std::io::Error),
OutputMp4Start(mp4::Error),
OutputMp4AddTrack(mp4::Error),
OutputMp4WriteSample(mp4::Error),
OutputMp4End(mp4::Error),
}
struct EncodeParams{
@@ -154,9 +156,41 @@ fn encode(params:EncodeParams)->Result<(),EncodeError>{
)
.map_err(EncodeError::VideoCreateTextures)?;
let mut output_file = std::fs::File::create(params.output_file)
let output_file=std::fs::File::create(params.output_file)
.map_err(EncodeError::OutputCreateFile)?;
let mp4_config=mp4::Mp4Config{
major_brand: str::parse("isom").unwrap(),
minor_version: 512,
compatible_brands: vec![
str::parse("isom").unwrap(),
str::parse("iso2").unwrap(),
str::parse("avc1").unwrap(),
str::parse("mp41").unwrap(),
],
timescale:target_framerate,
};
let mut mp4=mp4::Mp4Writer::write_start(output_file,&mp4_config)
.map_err(EncodeError::OutputMp4Start)?;
let avc_config=mp4::AvcConfig{
width:params.width.get() as u16,
height:params.height.get() as u16,
// make up some data to prevent this underdeveloped library from crashing
seq_param_set:vec![0,0,0,0],
pic_param_set:vec![],
};
let track_config=mp4::TrackConfig{
track_type:mp4::TrackType::Video,
timescale:target_framerate,
language:"eng".to_owned(),
media_conf:mp4::MediaConfig::AvcConfig(avc_config),
};
const TRACK_ID:u32=1;
mp4.add_track(&track_config)
.map_err(EncodeError::OutputMp4AddTrack)?;
let duration = bot.duration();
for i in 0..duration.get()*target_framerate as i64/SessionTime::ONE_SECOND.get() {
let time=SessionTime::raw(i*SessionTime::ONE_SECOND.get()/target_framerate as i64);
@@ -171,10 +205,20 @@ fn encode(params:EncodeParams)->Result<(),EncodeError>{
let res=unsafe{encoder.encode(frame,false)}
.map_err(EncodeError::VideoEncodeFrame)?;
output_file.write_all(&res.data)
.map_err(EncodeError::OutputWriteFile)?;
let mp4_sample=mp4::Mp4Sample{
start_time:i as u64,
duration:1,
rendering_offset:0,
is_sync:false,
bytes:res.data.into(),
};
mp4.write_sample(TRACK_ID,&mp4_sample)
.map_err(EncodeError::OutputMp4WriteSample)?;
}
mp4.write_end()
.map_err(EncodeError::OutputMp4End)?;
Ok(())
}