binkmux: hopefully set audio codec flags correctly this time
[nihav.git] / nihav-rad / src / muxers / bink.rs
CommitLineData
c7410bf5
KS
1use nihav_core::muxers::*;
2use std::collections::VecDeque;
3
4const ASSEMBLE_DEPTH: usize = 32;
5
6struct BinkMuxer<'a> {
7 bw: &'a mut ByteWriter<'a>,
8 naudio: usize,
9 maxsize: u32,
10 nframes: usize,
11 index: Vec<u32>,
12 index_start: u64,
13 data_start: u64,
14
15 video_parts: VecDeque<(NABufferRef<Vec<u8>>, bool)>,
16 audio_parts: Vec<VecDeque<NABufferRef<Vec<u8>>>>,
17 alen: Vec<u32>,
18}
19
20impl<'a> BinkMuxer<'a> {
21 fn new(bw: &'a mut ByteWriter<'a>) -> Self {
22 Self {
23 bw,
24 naudio: 0,
25 maxsize: 0,
26 nframes: 0,
27 index: Vec::new(),
28 index_start: 0,
29 data_start: 0,
30
31 video_parts: VecDeque::with_capacity(ASSEMBLE_DEPTH),
32 audio_parts: Vec::new(),
33 alen: Vec::new(),
34 }
35 }
36 fn write_frame(&mut self, flush: bool) -> MuxerResult<bool> {
37 if self.video_parts.is_empty() {
38 return Ok(false);
39 }
40 let has_audio = flush || self.audio_parts.iter().fold(true, |acc, apart| acc & !apart.is_empty());
41
42 if !has_audio {
43 return Ok(false);
44 }
45
46 let (vbuf, kf) = self.video_parts.pop_front().unwrap();
47
48 let start = self.bw.tell();
49
50 for (apart, maxalen) in self.audio_parts.iter_mut().zip(self.alen.iter_mut()) {
51 if let Some(buf) = apart.pop_front() {
52 validate!(buf.len() > 4);
53 let alen = read_u32le(&buf)?;
54 *maxalen = (*maxalen).max(alen);
55 self.bw.write_u32le(buf.len() as u32)?;
56 self.bw.write_buf(&buf)?;
57 } else {
58 self.bw.write_u32le(0)?;
59 }
60 }
61 self.bw.write_buf(&vbuf)?;
62 if (self.bw.tell() & 1) != 0 {
63 self.bw.write_byte(0)?; // padding
64 }
65 let frame_size = (self.bw.tell() - start) as u32;
66 self.maxsize = self.maxsize.max(frame_size);
67 let mut ix = start as u32;
68 if kf {
69 ix |= 1;
70 }
71 self.index.push(ix);
72
73 Ok(true)
74 }
75}
76
77impl<'a> MuxCore<'a> for BinkMuxer<'a> {
78 fn create(&mut self, strmgr: &StreamManager) -> MuxerResult<()> {
79 if strmgr.get_num_streams() == 0 {
80 return Err(MuxerError::InvalidArgument);
81 }
82 if strmgr.get_num_streams() > 257 {
83 return Err(MuxerError::UnsupportedFormat);
84 }
85 let vstream = strmgr.get_stream(0).unwrap();
86 if vstream.get_media_type() != StreamType::Video {
87 println!("bink: first stream must be video");
88 return Err(MuxerError::UnsupportedFormat);
89 }
90 let info = vstream.get_info();
91 if !matches!(info.get_name(), "bink-video" | "bink2-video") {
92 return Err(MuxerError::UnsupportedFormat);
93 }
94 for strm in strmgr.iter().skip(1) {
95 if strm.get_media_type() == StreamType::Audio {
96 if !matches!(strm.get_info().get_name(), "bink-audio-dct" | "bink-audio-rdft") {
97 return Err(MuxerError::UnsupportedFormat);
98 }
99 self.naudio += 1;
100 } else {
101 return Err(MuxerError::UnsupportedFormat);
102 }
103 }
104
105 //todo determine nframes properly
106 self.nframes = vstream.get_duration() as usize;
107 if self.nframes == 0 {
108 println!("Cannot create Bink file with an undefined number of frames\n");
109 return Err(MuxerError::NotImplemented);
110 }
111
112 // video header
113 if let Some(edata) = info.get_extradata() {
114 let vinfo = info.get_properties().get_video_info().unwrap();
115 validate!(edata.len() >= 8);
116 self.bw.write_buf(&edata[..4])?;
117 self.bw.write_u32le(0)?; // file size
118 self.bw.write_u32le(0)?; // number of frames
119 self.bw.write_u32le(0)?; // largest frame size
120 self.bw.write_u32le(0)?; // number of frames again
121 self.bw.write_u32le(vinfo.width as u32)?;
122 self.bw.write_u32le(vinfo.height as u32)?;
123 self.bw.write_u32le(vstream.tb_den)?;
124 self.bw.write_u32le(vstream.tb_num)?;
125 self.bw.write_buf(&edata[4..8])?;
126 } else {
127 return Err(MuxerError::UnsupportedFormat);
128 }
129
130 // audio header
131 self.bw.write_u32le(self.naudio as u32)?;
132//xxx: some KB2 field
133 for _ in 0..self.naudio {
134 self.bw.write_u32le(0)?; // max audio frame duration
135 }
136 for astrm in strmgr.iter().skip(1) {
137 let info = astrm.get_info();
138 let ainfo = info.get_properties().get_audio_info().unwrap();
139 self.bw.write_u24le(ainfo.sample_rate)?;
140 let mut flags = 0;
141 if info.get_name() == "bink-audio-dct" {
142 flags |= 0x10;
86b51082
KS
143 flags |= 0x40;
144 }
145 if info.get_name() == "bink-audio-rdft" {
146 flags |= 0x80;
c7410bf5
KS
147 }
148 if ainfo.channels == 2 {
149 flags |= 0x20;
c7410bf5
KS
150 }
151 self.bw.write_byte(flags)?;
152 }
153 for i in 0..self.naudio {
154 self.bw.write_u32le(i as u32)?;
155 }
156
157 for _ in 0..self.naudio {
158 self.audio_parts.push(VecDeque::with_capacity(ASSEMBLE_DEPTH));
159 self.alen.push(0);
160 }
161
162 self.index_start = self.bw.tell();
163 for _ in 0..=self.nframes {
164 self.bw.write_u32le(0)?;
165 }
166
167 self.data_start = self.bw.tell();
168
169 Ok(())
170 }
171 fn mux_frame(&mut self, _strmgr: &StreamManager, pkt: NAPacket) -> MuxerResult<()> {
172 if self.data_start == 0 {
173 return Err(MuxerError::NotCreated);
174 }
175 let stream = pkt.get_stream();
176 let str_num = stream.get_num();
177 let src = pkt.get_buffer();
178 if str_num == 0 { // video
179 self.video_parts.push_back((src, pkt.is_keyframe()));
180 if self.video_parts.len() >= ASSEMBLE_DEPTH {
181 while self.write_frame(false)? {
182 }
183 }
184 if self.video_parts.len() >= ASSEMBLE_DEPTH {
185 self.write_frame(true)?;
186 }
187 } else {
188 self.audio_parts[str_num - 1].push_back(src);
189 }
190
191 Ok(())
192 }
193 fn flush(&mut self) -> MuxerResult<()> {
194 Ok(())
195 }
196 fn end(&mut self) -> MuxerResult<()> {
197 while self.write_frame(true)? {
198 }
199
200 let full_size = self.bw.tell();
201
202 //xxx: if index.len() <= nframes move data back and patch index and full_size
203
204 self.index.push(self.bw.tell() as u32);
205
206 self.bw.seek(SeekFrom::Start(4))?;
207 self.bw.write_u32le((full_size - 8) as u32)?;
208 self.bw.write_u32le(self.index.len() as u32 - 1)?;
209 self.bw.write_u32le(self.maxsize)?;
210 self.bw.write_u32le(self.index.len() as u32 - 1)?;
211
212 self.bw.seek(SeekFrom::Start(44))?; //xxx: or 48 for Bink2
213 for &alen in self.alen.iter() {
214 self.bw.write_u32le(alen)?;
215 }
216
217 self.bw.seek(SeekFrom::Start(self.index_start))?;
218 for &idx in self.index.iter() {
219 self.bw.write_u32le(idx)?;
220 }
221 Ok(())
222 }
223}
224
225impl<'a> NAOptionHandler for BinkMuxer<'a> {
226 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
227 fn set_options(&mut self, _options: &[NAOption]) { }
228 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
229}
230
231pub struct BinkMuxerCreator {}
232
233impl MuxerCreator for BinkMuxerCreator {
234 fn new_muxer<'a>(&self, bw: &'a mut ByteWriter<'a>) -> Box<dyn MuxCore<'a> + 'a> {
235 Box::new(BinkMuxer::new(bw))
236 }
237 fn get_name(&self) -> &'static str { "bink" }
238 fn get_capabilities(&self) -> MuxerCapabilities { MuxerCapabilities::Universal }
239}
240
241#[cfg(test)]
242mod test {
243 use nihav_core::codecs::*;
244 use nihav_core::demuxers::*;
245 use nihav_core::muxers::*;
246 use nihav_codec_support::test::enc_video::*;
247 use crate::*;
248
249 #[test]
250 fn test_bink_muxer() {
251 let mut dmx_reg = RegisteredDemuxers::new();
252 rad_register_all_demuxers(&mut dmx_reg);
253 //test sample: https://samples.mplayerhq.hu/game-formats/bink/ActivisionLogo
254 let dec_config = DecoderTestParams {
255 demuxer: "bink",
256 in_name: "assets/RAD/ActivisionLogo.bik",
257 limit: None,
258 stream_type: StreamType::None,
259 dmx_reg, dec_reg: RegisteredDecoders::new(),
260 };
261 let mut mux_reg = RegisteredMuxers::new();
262 rad_register_all_muxers(&mut mux_reg);
263 /*let enc_config = EncoderTestParams {
264 muxer: "bink",
265 enc_name: "",
266 out_name: "muxed.bink",
267 mux_reg, enc_reg: RegisteredEncoders::new(),
268 };
269 test_remuxing(&dec_config, &enc_config);*/
270 test_remuxing_md5(&dec_config, "bink", &mux_reg,
271 [0x98e1892c, 0xcac2f087, 0x7350256e, 0xc71c927a]);
272 }
273}