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" {
145 if info.get_name() == "bink-audio-rdft" {
148 if ainfo.channels == 2 {
151 self.bw.write_byte(flags)?;
153 for i in 0..self.naudio {
154 self.bw.write_u32le(i as u32)?;
157 for _ in 0..self.naudio {
158 self.audio_parts.push(VecDeque::with_capacity(ASSEMBLE_DEPTH));
162 self.index_start = self.bw.tell();
163 for _ in 0..=self.nframes {
164 self.bw.write_u32le(0)?;
167 self.data_start = self.bw.tell();
171 fn mux_frame(&mut self, _strmgr: &StreamManager, pkt: NAPacket) -> MuxerResult<()> {
172 if self.data_start == 0 {
173 return Err(MuxerError::NotCreated);
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)? {
184 if self.video_parts.len() >= ASSEMBLE_DEPTH {
185 self.write_frame(true)?;
188 self.audio_parts[str_num - 1].push_back(src);
193 fn flush(&mut self) -> MuxerResult<()> {
196 fn end(&mut self) -> MuxerResult<()> {
197 while self.write_frame(true)? {
200 let full_size = self.bw.tell();
202 //xxx: if index.len() <= nframes move data back and patch index and full_size
204 self.index.push(self.bw.tell() as u32);
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)?;
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)?;
217 self.bw.seek(SeekFrom::Start(self.index_start))?;
218 for &idx in self.index.iter() {
219 self.bw.write_u32le(idx)?;
225 impl<'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 }
231 pub struct BinkMuxerCreator {}
233 impl 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))
237 fn get_name(&self) -> &'static str { "bink" }
238 fn get_capabilities(&self) -> MuxerCapabilities { MuxerCapabilities::Universal }
243 use nihav_core::codecs::*;
244 use nihav_core::demuxers::*;
245 use nihav_core::muxers::*;
246 use nihav_codec_support::test::enc_video::*;
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 {
256 in_name: "assets/RAD/ActivisionLogo.bik",
258 stream_type: StreamType::None,
259 dmx_reg, dec_reg: RegisteredDecoders::new(),
261 let mut mux_reg = RegisteredMuxers::new();
262 rad_register_all_muxers(&mut mux_reg);
263 /*let enc_config = EncoderTestParams {
266 out_name: "muxed.bink",
267 mux_reg, enc_reg: RegisteredEncoders::new(),
269 test_remuxing(&dec_config, &enc_config);*/
270 test_remuxing_md5(&dec_config, "bink", &mux_reg,
271 [0x98e1892c, 0xcac2f087, 0x7350256e, 0xc71c927a]);