aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKostya Shishkov <kostya.shishkov@gmail.com>2021-09-30 13:49:50 +0200
committerKostya Shishkov <kostya.shishkov@gmail.com>2023-11-11 15:17:05 +0100
commit2d94f690936af4c2279b1e284ea7cb93ffe71717 (patch)
treeb56e9f28e90211086ed208d2f1beb8bf92c5285f
parentfcdf9a8a5632dcdd6bac3068e7eb2098d9e13246 (diff)
downloadnihav-2d94f690936af4c2279b1e284ea7cb93ffe71717.tar.gz
EA muxer
-rw-r--r--nihav-allstuff/src/lib.rs1
-rw-r--r--nihav-game/Cargo.toml6
-rw-r--r--nihav-game/src/lib.rs3
-rw-r--r--nihav-game/src/muxers/ea.rs161
-rw-r--r--nihav-game/src/muxers/mod.rs15
5 files changed, 185 insertions, 1 deletions
diff --git a/nihav-allstuff/src/lib.rs b/nihav-allstuff/src/lib.rs
index ec41d7e..3b6d60f 100644
--- a/nihav-allstuff/src/lib.rs
+++ b/nihav-allstuff/src/lib.rs
@@ -85,6 +85,7 @@ pub fn nihav_register_all_encoders(re: &mut RegisteredEncoders) {
pub fn nihav_register_all_muxers(rm: &mut RegisteredMuxers) {
flash_register_all_muxers(rm);
generic_register_all_muxers(rm);
+ game_register_all_muxers(rm);
llaudio_register_all_muxers(rm);
rad_register_all_muxers(rm);
realmedia_register_all_muxers(rm);
diff --git a/nihav-game/Cargo.toml b/nihav-game/Cargo.toml
index 652fd67..9111b9a 100644
--- a/nihav-game/Cargo.toml
+++ b/nihav-game/Cargo.toml
@@ -16,7 +16,7 @@ features = ["qmf"]
nihav_commonfmt = { path = "../nihav-commonfmt", default-features=false, features = ["all_demuxers"] }
[features]
-default = ["all_decoders", "all_demuxers"]
+default = ["all_decoders", "all_demuxers", "all_muxers"]
demuxers = []
all_demuxers = ["demuxer_bmv", "demuxer_bmv3", "demuxer_cnm", "demuxer_fcmp", "demuxer_fst", "demuxer_gdv", "demuxer_hl_fmv", "demuxer_imax", "demuxer_q", "demuxer_sga", "demuxer_siff", "demuxer_smush", "demuxer_vmd", "demuxer_vx"]
demuxer_bmv = ["demuxers"]
@@ -60,3 +60,7 @@ all_audio_decoders = ["decoder_fstaud", "decoder_lhst500f22", "decoder_smush_aud
decoder_fstaud = ["decoders"]
decoder_lhst500f22 = ["decoders"]
decoder_smush_audio = ["decoders"]
+
+all_muxers = ["muxer_ea"]
+muxers = []
+muxer_ea = ["muxers"] \ No newline at end of file
diff --git a/nihav-game/src/lib.rs b/nihav-game/src/lib.rs
index e0187ae..2a568d9 100644
--- a/nihav-game/src/lib.rs
+++ b/nihav-game/src/lib.rs
@@ -20,3 +20,6 @@ pub use crate::codecs::game_register_all_decoders;
#[allow(clippy::upper_case_acronyms)]
mod demuxers;
pub use crate::demuxers::game_register_all_demuxers;
+
+mod muxers;
+pub use crate::muxers::game_register_all_muxers;
diff --git a/nihav-game/src/muxers/ea.rs b/nihav-game/src/muxers/ea.rs
new file mode 100644
index 0000000..4da1fc6
--- /dev/null
+++ b/nihav-game/src/muxers/ea.rs
@@ -0,0 +1,161 @@
+use nihav_core::muxers::*;
+
+struct EAMuxer<'a> {
+ bw: &'a mut ByteWriter<'a>,
+ has_alpha: bool,
+ nframes: u32,
+ max_size: [u32; 2],
+}
+
+impl<'a> EAMuxer<'a> {
+ fn new(bw: &'a mut ByteWriter<'a>) -> Self {
+ Self {
+ bw,
+ has_alpha: false,
+ nframes: 0,
+ max_size: [0; 2],
+ }
+ }
+}
+
+impl<'a> MuxCore<'a> for EAMuxer<'a> {
+ #[allow(clippy::unreadable_literal)]
+ #[allow(clippy::cast_lossless)]
+ fn create(&mut self, strmgr: &StreamManager) -> MuxerResult<()> {
+ if strmgr.get_num_streams() == 0 {
+ return Err(MuxerError::InvalidArgument);
+ }
+
+ let mut nvideo = 0;
+ for stream in strmgr.iter() {
+ if stream.get_media_type() == StreamType::Video {
+ if stream.get_info().get_name() != "vp6" {
+ return Err(MuxerError::UnsupportedFormat);
+ }
+ nvideo += 1;
+ } else {
+ return Err(MuxerError::UnsupportedFormat);
+ }
+ }
+ if nvideo == 0 || nvideo > 2 {
+ return Err(MuxerError::UnsupportedFormat);
+ }
+ self.has_alpha = nvideo == 2;
+
+ if self.has_alpha {
+ self.bw.write_buf(b"AVP6\x08\x00\x00\x00")?;
+ }
+ for (str_no, stream) in strmgr.iter().enumerate() {
+ if let NACodecTypeInfo::Video(ref vinfo) = stream.get_info().get_properties() {
+ let tag = if str_no == 0 { b"MVhd" } else { b"AVhd" };
+
+ self.bw.write_buf(tag)?;
+ self.bw.write_u32le(0x20)?;
+ self.bw.write_buf(b"vp60")?;
+ self.bw.write_u16le(vinfo.width as u16)?;
+ self.bw.write_u16le(vinfo.height as u16)?;
+ self.bw.write_u32le(0)?;
+ self.bw.write_u32le(0)?;
+ self.bw.write_u32le(stream.tb_den)?;
+ self.bw.write_u32le(stream.tb_num)?;
+ } else {
+ unimplemented!();
+ }
+ }
+
+ Ok(())
+ }
+ #[allow(clippy::collapsible_else_if)]
+ fn mux_frame(&mut self, _strmgr: &StreamManager, pkt: NAPacket) -> MuxerResult<()> {
+ let stream = pkt.get_stream();
+ let str_num = stream.get_num();
+ if str_num > 2 {
+ return Err(MuxerError::UnsupportedFormat);
+ }
+
+ let chunk_len = pkt.get_buffer().len() as u32;
+
+ let tag = if pkt.is_keyframe() {
+ if str_num == 0 { b"MV0K" } else { b"AV0K" }
+ } else {
+ if str_num == 0 { b"MV0F" } else { b"AV0F" }
+ };
+ self.max_size[str_num] = self.max_size[str_num].max(pkt.get_buffer().len() as u32);
+ self.bw.write_buf(tag)?;
+ self.bw.write_u32le(chunk_len + 8)?;
+ self.bw.write_buf(&pkt.get_buffer())?;
+
+ if str_num == 0 {
+ self.nframes += 1;
+ }
+
+ Ok(())
+ }
+ fn flush(&mut self) -> MuxerResult<()> {
+ Ok(())
+ }
+ fn end(&mut self) -> MuxerResult<()> {
+ if !self.has_alpha {
+ self.bw.seek(SeekFrom::Start(0x10))?;
+ self.bw.write_u32le(self.nframes)?;
+ self.bw.write_u32le(self.max_size[0])?;
+ } else {
+ self.bw.seek(SeekFrom::Start(0x18))?;
+ self.bw.write_u32le(self.nframes)?;
+ self.bw.write_u32le(self.max_size[0])?;
+ self.bw.seek(SeekFrom::Start(0x38))?;
+ self.bw.write_u32le(self.nframes)?;
+ self.bw.write_u32le(self.max_size[1])?;
+ }
+ Ok(())
+ }
+}
+
+impl<'a> NAOptionHandler for EAMuxer<'a> {
+ fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+ fn set_options(&mut self, _options: &[NAOption]) { }
+ fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub struct EAMuxerCreator {}
+
+impl MuxerCreator for EAMuxerCreator {
+ fn new_muxer<'a>(&self, bw: &'a mut ByteWriter<'a>) -> Box<dyn MuxCore<'a> + 'a> {
+ Box::new(EAMuxer::new(bw))
+ }
+ fn get_name(&self) -> &'static str { "ea" }
+ fn get_capabilities(&self) -> MuxerCapabilities { MuxerCapabilities::OnlyVideo }
+}
+
+#[cfg(test)]
+mod test {
+ use nihav_core::codecs::*;
+ use nihav_core::demuxers::*;
+ use nihav_core::muxers::*;
+ use nihav_codec_support::test::enc_video::*;
+ use crate::*;
+
+ #[test]
+ fn test_ea_muxer() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ nihav_commonfmt::generic_register_all_demuxers(&mut dmx_reg);
+ let dec_config = DecoderTestParams {
+ demuxer: "avi",
+ in_name: "assets/Duck/vp6_crash.avi",
+ limit: None,
+ stream_type: StreamType::None,
+ dmx_reg, dec_reg: RegisteredDecoders::new(),
+ };
+ let mut mux_reg = RegisteredMuxers::new();
+ game_register_all_muxers(&mut mux_reg);
+ /*let enc_config = EncoderTestParams {
+ muxer: "ea",
+ enc_name: "",
+ out_name: "muxed.ea",
+ mux_reg, enc_reg: RegisteredEncoders::new(),
+ };
+ test_remuxing(&dec_config, &enc_config);*/
+ test_remuxing_md5(&dec_config, "ea", &mux_reg,
+ [0xc8c6484d, 0x863de1ae, 0x97a38a31, 0x59e2a7ef]);
+ }
+}
diff --git a/nihav-game/src/muxers/mod.rs b/nihav-game/src/muxers/mod.rs
new file mode 100644
index 0000000..b609072
--- /dev/null
+++ b/nihav-game/src/muxers/mod.rs
@@ -0,0 +1,15 @@
+use nihav_core::muxers::*;
+
+#[cfg(feature="muxer_ea")]
+mod ea;
+
+const MUXERS: &[&dyn MuxerCreator] = &[
+#[cfg(feature="muxer_ea")]
+ &ea::EAMuxerCreator {},
+];
+
+pub fn game_register_all_muxers(rm: &mut RegisteredMuxers) {
+ for muxer in MUXERS.iter() {
+ rm.add_muxer(*muxer);
+ }
+}