1 use nihav_core::muxers::*;
2 use std::collections::VecDeque;
4 const ASSEMBLE_DEPTH: usize = 32;
7 bw: &'a mut ByteWriter<'a>,
15 video_parts: VecDeque<(NABufferRef<Vec<u8>>, bool)>,
16 audio_parts: Vec<VecDeque<NABufferRef<Vec<u8>>>>,
20 impl<'a> BinkMuxer<'a> {
21 fn new(bw: &'a mut ByteWriter<'a>) -> Self {
31 video_parts: VecDeque::with_capacity(ASSEMBLE_DEPTH),
32 audio_parts: Vec::new(),
36 fn write_frame(&mut self, flush: bool) -> MuxerResult<bool> {
37 if self.video_parts.is_empty() {
40 let has_audio = flush || self.audio_parts.iter().fold(true, |acc, apart| acc & !apart.is_empty());
46 let (vbuf, kf) = self.video_parts.pop_front().unwrap();
48 let start = self.bw.tell();
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)?;
58 self.bw.write_u32le(0)?;
61 self.bw.write_buf(&vbuf)?;
62 if (self.bw.tell() & 1) != 0 {
63 self.bw.write_byte(0)?; // padding
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;
77 impl<'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);
82 if strmgr.get_num_streams() > 257 {
83 return Err(MuxerError::UnsupportedFormat);
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);
90 let info = vstream.get_info();
91 if !matches!(info.get_name(), "bink-video" | "bink2-video") {
92 return Err(MuxerError::UnsupportedFormat);
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);
101 return Err(MuxerError::UnsupportedFormat);
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);
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])?;
127 return Err(MuxerError::UnsupportedFormat);
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
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)?;
141 if info.get_name() == "bink-audio-dct" {
144 if ainfo.channels == 2 {
147 if flags == 0x30 { // seems to be common
150 self.bw.write_byte(flags)?;
152 for i in 0..self.naudio {
153 self.bw.write_u32le(i as u32)?;
156 for _ in 0..self.naudio {
157 self.audio_parts.push(VecDeque::with_capacity(ASSEMBLE_DEPTH));
161 self.index_start = self.bw.tell();
162 for _ in 0..=self.nframes {
163 self.bw.write_u32le(0)?;
166 self.data_start = self.bw.tell();
170 fn mux_frame(&mut self, _strmgr: &StreamManager, pkt: NAPacket) -> MuxerResult<()> {
171 if self.data_start == 0 {
172 return Err(MuxerError::NotCreated);
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)? {
183 if self.video_parts.len() >= ASSEMBLE_DEPTH {
184 self.write_frame(true)?;
187 self.audio_parts[str_num - 1].push_back(src);
192 fn flush(&mut self) -> MuxerResult<()> {
195 fn end(&mut self) -> MuxerResult<()> {
196 while self.write_frame(true)? {
199 let full_size = self.bw.tell();
201 //xxx: if index.len() <= nframes move data back and patch index and full_size
203 self.index.push(self.bw.tell() as u32);
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)?;
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)?;
216 self.bw.seek(SeekFrom::Start(self.index_start))?;
217 for &idx in self.index.iter() {
218 self.bw.write_u32le(idx)?;
224 impl<'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 }
230 pub struct BinkMuxerCreator {}
232 impl 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))
236 fn get_name(&self) -> &'static str { "bink" }
237 fn get_capabilities(&self) -> MuxerCapabilities { MuxerCapabilities::Universal }
242 use nihav_core::codecs::*;
243 use nihav_core::demuxers::*;
244 use nihav_core::muxers::*;
245 use nihav_codec_support::test::enc_video::*;
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 {
255 in_name: "assets/RAD/ActivisionLogo.bik",
257 stream_type: StreamType::None,
258 dmx_reg, dec_reg: RegisteredDecoders::new(),
260 let mut mux_reg = RegisteredMuxers::new();
261 rad_register_all_muxers(&mut mux_reg);
262 /*let enc_config = EncoderTestParams {
265 out_name: "muxed.bink",
266 mux_reg, enc_reg: RegisteredEncoders::new(),
268 test_remuxing(&dec_config, &enc_config);*/
269 test_remuxing_md5(&dec_config, "bink", &mux_reg,
270 [0x98e1892c, 0xcac2f087, 0x7350256e, 0xc71c927a]);