Bink muxer
[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;
143 }
144 if ainfo.channels == 2 {
145 flags |= 0x20;
146 }
147 if flags == 0x30 { // seems to be common
148 flags = 0x70;
149 }
150 self.bw.write_byte(flags)?;
151 }
152 for i in 0..self.naudio {
153 self.bw.write_u32le(i as u32)?;
154 }
155
156 for _ in 0..self.naudio {
157 self.audio_parts.push(VecDeque::with_capacity(ASSEMBLE_DEPTH));
158 self.alen.push(0);
159 }
160
161 self.index_start = self.bw.tell();
162 for _ in 0..=self.nframes {
163 self.bw.write_u32le(0)?;
164 }
165
166 self.data_start = self.bw.tell();
167
168 Ok(())
169 }
170 fn mux_frame(&mut self, _strmgr: &StreamManager, pkt: NAPacket) -> MuxerResult<()> {
171 if self.data_start == 0 {
172 return Err(MuxerError::NotCreated);
173 }
174 let stream = pkt.get_stream();
175 let str_num = stream.get_num();
176 let src = pkt.get_buffer();
177 if str_num == 0 { // video
178 self.video_parts.push_back((src, pkt.is_keyframe()));
179 if self.video_parts.len() >= ASSEMBLE_DEPTH {
180 while self.write_frame(false)? {
181 }
182 }
183 if self.video_parts.len() >= ASSEMBLE_DEPTH {
184 self.write_frame(true)?;
185 }
186 } else {
187 self.audio_parts[str_num - 1].push_back(src);
188 }
189
190 Ok(())
191 }
192 fn flush(&mut self) -> MuxerResult<()> {
193 Ok(())
194 }
195 fn end(&mut self) -> MuxerResult<()> {
196 while self.write_frame(true)? {
197 }
198
199 let full_size = self.bw.tell();
200
201 //xxx: if index.len() <= nframes move data back and patch index and full_size
202
203 self.index.push(self.bw.tell() as u32);
204
205 self.bw.seek(SeekFrom::Start(4))?;
206 self.bw.write_u32le((full_size - 8) as u32)?;
207 self.bw.write_u32le(self.index.len() as u32 - 1)?;
208 self.bw.write_u32le(self.maxsize)?;
209 self.bw.write_u32le(self.index.len() as u32 - 1)?;
210
211 self.bw.seek(SeekFrom::Start(44))?; //xxx: or 48 for Bink2
212 for &alen in self.alen.iter() {
213 self.bw.write_u32le(alen)?;
214 }
215
216 self.bw.seek(SeekFrom::Start(self.index_start))?;
217 for &idx in self.index.iter() {
218 self.bw.write_u32le(idx)?;
219 }
220 Ok(())
221 }
222}
223
224impl<'a> NAOptionHandler for BinkMuxer<'a> {
225 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
226 fn set_options(&mut self, _options: &[NAOption]) { }
227 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
228}
229
230pub struct BinkMuxerCreator {}
231
232impl MuxerCreator for BinkMuxerCreator {
233 fn new_muxer<'a>(&self, bw: &'a mut ByteWriter<'a>) -> Box<dyn MuxCore<'a> + 'a> {
234 Box::new(BinkMuxer::new(bw))
235 }
236 fn get_name(&self) -> &'static str { "bink" }
237 fn get_capabilities(&self) -> MuxerCapabilities { MuxerCapabilities::Universal }
238}
239
240#[cfg(test)]
241mod test {
242 use nihav_core::codecs::*;
243 use nihav_core::demuxers::*;
244 use nihav_core::muxers::*;
245 use nihav_codec_support::test::enc_video::*;
246 use crate::*;
247
248 #[test]
249 fn test_bink_muxer() {
250 let mut dmx_reg = RegisteredDemuxers::new();
251 rad_register_all_demuxers(&mut dmx_reg);
252 //test sample: https://samples.mplayerhq.hu/game-formats/bink/ActivisionLogo
253 let dec_config = DecoderTestParams {
254 demuxer: "bink",
255 in_name: "assets/RAD/ActivisionLogo.bik",
256 limit: None,
257 stream_type: StreamType::None,
258 dmx_reg, dec_reg: RegisteredDecoders::new(),
259 };
260 let mut mux_reg = RegisteredMuxers::new();
261 rad_register_all_muxers(&mut mux_reg);
262 /*let enc_config = EncoderTestParams {
263 muxer: "bink",
264 enc_name: "",
265 out_name: "muxed.bink",
266 mux_reg, enc_reg: RegisteredEncoders::new(),
267 };
268 test_remuxing(&dec_config, &enc_config);*/
269 test_remuxing_md5(&dec_config, "bink", &mux_reg,
270 [0x98e1892c, 0xcac2f087, 0x7350256e, 0xc71c927a]);
271 }
272}