forked from StrafesNET/roblox-bot-player
encode command
This commit is contained in:
@@ -1,9 +1,104 @@
|
||||
use std::io::Write;
|
||||
use std::num::NonZeroU32;
|
||||
use std::path::PathBuf;
|
||||
use strafesnet_common::session::Time as SessionTime;
|
||||
|
||||
pub fn main(){
|
||||
#[derive(clap::Subcommand)]
|
||||
pub enum Commands{
|
||||
Encode(EncodeSubcommand),
|
||||
}
|
||||
|
||||
impl Commands{
|
||||
pub fn run(self){
|
||||
match self{
|
||||
Commands::Encode(command)=>command.run().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(clap::Args)]
|
||||
pub struct EncodeSubcommand{
|
||||
#[arg(long,short)]
|
||||
map:PathBuf,
|
||||
#[arg(long,short)]
|
||||
bot:PathBuf,
|
||||
#[arg(long,short)]
|
||||
output_file:Option<PathBuf>,
|
||||
#[arg(long,short)]
|
||||
width:Option<NonZeroU32>,
|
||||
#[arg(long,short)]
|
||||
height:Option<NonZeroU32>,
|
||||
#[arg(long)]
|
||||
fps:Option<u32>,
|
||||
#[arg(long)]
|
||||
target_bitrate:Option<u64>,
|
||||
#[arg(long)]
|
||||
max_bitrate:Option<u64>,
|
||||
#[arg(long)]
|
||||
device:Option<String>,
|
||||
}
|
||||
impl EncodeSubcommand{
|
||||
fn run(self)->Result<(),EncodeError>{
|
||||
encode(EncodeParams{
|
||||
width:self.width.unwrap_or(NonZeroU32::new(1920).unwrap()),
|
||||
height:self.width.unwrap_or(NonZeroU32::new(1080).unwrap()),
|
||||
target_framerate:self.fps.unwrap_or(60),
|
||||
average_bitrate:self.target_bitrate.unwrap_or(6_000_000),
|
||||
max_bitrate:self.max_bitrate.unwrap_or(6_000_000),
|
||||
device:self.device,
|
||||
map:self.map,
|
||||
bot:self.bot,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
#[derive(Debug)]
|
||||
enum EncodeError{
|
||||
ReadMap(std::io::Error),
|
||||
ReadBot(std::io::Error),
|
||||
DecodeSNF(strafesnet_snf::Error),
|
||||
DecodeMap(strafesnet_snf::map::Error),
|
||||
DecodeBot(strafesnet_roblox_bot_file::v0::Error),
|
||||
}
|
||||
|
||||
struct EncodeParams{
|
||||
width:NonZeroU32,
|
||||
height:NonZeroU32,
|
||||
target_framerate:u32,
|
||||
average_bitrate:u64,
|
||||
max_bitrate:u64,
|
||||
device:Option<String>,
|
||||
map:PathBuf,
|
||||
bot:PathBuf,
|
||||
}
|
||||
|
||||
fn encode(params:EncodeParams)->Result<(),EncodeError>{
|
||||
let size = glam::uvec2(params.width.get(),params.height.get());
|
||||
let target_framerate = params.target_framerate;
|
||||
let average_bitrate = params.average_bitrate;
|
||||
let max_bitrate = params.max_bitrate;
|
||||
|
||||
let map_file=std::fs::read(params.map).map_err(EncodeError::ReadMap)?;
|
||||
let bot_file=std::fs::read(params.bot).map_err(EncodeError::ReadBot)?;
|
||||
|
||||
// read files
|
||||
let map=strafesnet_snf::read_map(std::io::Cursor::new(map_file))
|
||||
.map_err(EncodeError::DecodeSNF)?
|
||||
.into_complete_map()
|
||||
.map_err(EncodeError::DecodeMap)?;
|
||||
let timelines=strafesnet_roblox_bot_file::v0::read_all_to_block(std::io::Cursor::new(bot_file))
|
||||
.map_err(EncodeError::DecodeBot)?;
|
||||
|
||||
let vulkan_instance = vk_video::VulkanInstance::new().unwrap();
|
||||
let vulkan_adapter = vulkan_instance.create_adapter(None).unwrap();
|
||||
let vulkan_adapter = if let Some(filter)=params.device.as_deref(){
|
||||
vulkan_instance.iter_adapters(None)
|
||||
.unwrap()
|
||||
.find(|adapter|adapter.info().name.contains(filter))
|
||||
.unwrap()
|
||||
}else{
|
||||
vulkan_instance.create_adapter(None).unwrap()
|
||||
};
|
||||
let vulkan_device = vulkan_adapter
|
||||
.create_device(
|
||||
wgpu::Features::TEXTURE_COMPRESSION_BC,
|
||||
@@ -12,18 +107,6 @@ pub fn main(){
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let size = glam::uvec2(1920,1080);
|
||||
let target_framerate = 60;
|
||||
let average_bitrate = 10_000_000;
|
||||
let max_bitrate = 20_000_000;
|
||||
|
||||
let bot_file=include_bytes!("../../web-demo/bhop_marble_7cf33a64-7120-4514-b9fa-4fe29d9523d.qbot");
|
||||
let map_file=include_bytes!("../../web-demo/bhop_marble_5692093612.snfm");
|
||||
|
||||
// decode
|
||||
let timelines=strafesnet_roblox_bot_file::v0::read_all_to_block(std::io::Cursor::new(bot_file)).unwrap();
|
||||
let map=strafesnet_snf::read_map(std::io::Cursor::new(map_file)).unwrap().into_complete_map().unwrap();
|
||||
|
||||
// playback
|
||||
let bot=strafesnet_roblox_bot_player::bot::CompleteBot::new(timelines);
|
||||
let mut playback_head=strafesnet_roblox_bot_player::head::PlaybackHead::new(&bot,SessionTime::ZERO);
|
||||
@@ -41,8 +124,8 @@ pub fn main(){
|
||||
vulkan_device
|
||||
.encoder_parameters_high_quality(
|
||||
vk_video::parameters::VideoParameters {
|
||||
width:size.x.try_into().unwrap(),
|
||||
height:size.y.try_into().unwrap(),
|
||||
width:params.width,
|
||||
height:params.height,
|
||||
target_framerate:target_framerate.into(),
|
||||
},
|
||||
vk_video::parameters::RateControl::VariableBitrate {
|
||||
@@ -78,6 +161,8 @@ pub fn main(){
|
||||
|
||||
output_file.write_all(&res.data).unwrap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct WgpuState {
|
||||
|
||||
24
video-encoder/src/main.rs
Normal file
24
video-encoder/src/main.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use clap::{Parser,Subcommand};
|
||||
|
||||
mod encode;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author,version,about,long_about=None)]
|
||||
#[command(propagate_version=true)]
|
||||
struct Cli{
|
||||
#[command(subcommand)]
|
||||
command:Commands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands{
|
||||
#[command(flatten)]
|
||||
Encode(encode::Commands),
|
||||
}
|
||||
|
||||
fn main(){
|
||||
let cli=Cli::parse();
|
||||
match cli.command{
|
||||
Commands::Encode(commands)=>commands.run(),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user