use nihav_core::demuxers::*;
use std::io::SeekFrom;
-const HEADER_SIZE: usize = 0x330;
+const OLD_HEADER_SIZE: usize = 0x330;
+const NEW_HEADER_SIZE: usize = 0x34;
+const HEADER1_SIZE: usize = 28;
+const HEADER2_OFF: usize = HEADER1_SIZE + 768;
const FRAME_HDR_SIZE: usize = 10;
const CHTYPE_VIDEO: u8 = 0x02;
aud_id: usize,
fno: usize,
is_indeo: bool,
+ is_lhaud: bool,
frames: Vec<FrameRec>,
}
impl<'a> DemuxCore<'a> for VMDDemuxer<'a> {
#[allow(unused_variables)]
- fn open(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
+ fn open(&mut self, strmgr: &mut StreamManager, _seek_index: &mut SeekIndex) -> DemuxerResult<()> {
let src = &mut self.src;
- let mut header: [u8; HEADER_SIZE] = [0; HEADER_SIZE];
- src.read_buf(&mut header)?;
+ let mut header: [u8; OLD_HEADER_SIZE] = [0; OLD_HEADER_SIZE];
+ src.read_buf(&mut header[..HEADER1_SIZE])?;
+ let hdr_size = read_u16le(&header)? as usize + 2;
+ validate!(hdr_size == OLD_HEADER_SIZE || hdr_size == NEW_HEADER_SIZE);
+ if hdr_size == OLD_HEADER_SIZE {
+ src.read_buf(&mut header[HEADER1_SIZE..][..768])?;
+ }
+ src.read_buf(&mut header[HEADER2_OFF..])?;
let mut width = read_u16le(&header[12..])? as usize;
let mut height = read_u16le(&header[14..])? as usize;
let nframes = read_u16le(&header[6..])? as usize;
let fpb = read_u16le(&header[18..])? as usize;
validate!(nframes > 0 && fpb > 0);
-
- let mut edata: Vec<u8> = Vec::with_capacity(HEADER_SIZE);
+
+ let mut edata: Vec<u8> = Vec::with_capacity(OLD_HEADER_SIZE);
edata.extend_from_slice(&header);
let vhdr = NAVideoInfo::new(width, height, false, PAL8_FORMAT);
let vci = NACodecTypeInfo::Video(vhdr);
let vinfo = NACodecInfo::new(if !self.is_indeo { "vmd-video" } else { "indeo3" }, vci, Some(edata));
self.vid_id = strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, 1, 12)).unwrap();
- let srate = read_u16le(&header[804..])? as u32;
+ let is_ext_audio = (hdr_size & 0xF) == 4;
+ let ext_audio_id = if is_ext_audio {
+ src.read_u16le()?
+ } else { 0 };
+ if is_ext_audio {
+ validate!(ext_audio_id >= 3 && ext_audio_id <= 6);
+ self.is_lhaud = true;
+ }
+ let srate = u32::from(read_u16le(&header[804..])?);
let block_size;
if srate > 0 {
let bsize = read_u16le(&header[806..])? as usize;
block_size = bsize;
}
+ let mut aedata: Vec<u8> = Vec::with_capacity(2);
+ aedata.extend_from_slice(&header[810..][..2]);
let ahdr = NAAudioInfo::new(srate, channels, if is16bit { SND_S16P_FORMAT } else { SND_U8_FORMAT }, block_size);
- let ainfo = NACodecInfo::new("vmd-audio", NACodecTypeInfo::Audio(ahdr), None);
+ let ac_name = if !is_ext_audio {
+ "vmd-audio"
+ } else {
+ match ext_audio_id {
+ 3 => "lhst15f8",
+ 4 => "lhst500f22",
+ 5 => "lhst250f11",
+ 6 => "lhst48",
+ _ => "unknown",
+ }
+ };
+ let ainfo = NACodecInfo::new(ac_name, NACodecTypeInfo::Audio(ahdr), Some(aedata));
self.aud_id = strmgr.add_stream(NAStream::new(StreamType::Audio, 1, ainfo, 1, srate)).unwrap();
} else {
block_size = 0;
}
- let adelay = read_u16le(&header[808..])? as u32;
- let idx_off = read_u32le(&header[812..])? as u64;
+ let adelay = u32::from(read_u16le(&header[808..])?);
+ let idx_off = u64::from(read_u32le(&header[812..])?);
src.seek(SeekFrom::Start(idx_off))?;
let mut offs: Vec<u32> = Vec::with_capacity(nframes);
for i in 0..nframes {
if self.fno >= self.frames.len() { return Err(DemuxerError::EOF); }
let cur_frame = &self.frames[self.fno];
//println!("fno {} -> type {} size {} @ {:X} ts {}", self.fno, cur_frame.chtype, cur_frame.size, cur_frame.off, cur_frame.ts);
- let next_pos = cur_frame.off as u64;
+ let next_pos = u64::from(cur_frame.off);
if self.src.tell() != next_pos {
self.src.seek(SeekFrom::Start(next_pos))?;
}
let is_video = cur_frame.chtype == CHTYPE_VIDEO;
let mut buf: Vec<u8> = Vec::with_capacity(FRAME_HDR_SIZE + (cur_frame.size as usize));
- if !self.is_indeo || !is_video {
+ if !(is_video && self.is_indeo) && !(!is_video && self.is_lhaud) {
buf.extend_from_slice(&cur_frame.hdr);
buf.resize(FRAME_HDR_SIZE + (cur_frame.size as usize), 0);
self.src.read_buf(&mut buf[FRAME_HDR_SIZE..])?;
let str_id = if is_video { self.vid_id } else { self.aud_id };
let str = strmgr.get_stream(str_id).unwrap();
let (tb_num, tb_den) = str.get_timebase();
- let ts = NATimeInfo::new(Some(cur_frame.ts as u64), None, None, tb_num, tb_den);
+ let ts = NATimeInfo::new(Some(u64::from(cur_frame.ts)), None, None, tb_num, tb_den);
let pkt = NAPacket::new(str, ts, false, buf);
Ok(pkt)
}
- #[allow(unused_variables)]
- fn seek(&mut self, time: u64) -> DemuxerResult<()> {
- Err(DemuxerError::NotImplemented)
+ fn seek(&mut self, _time: u64, _seek_index: &SeekIndex) -> DemuxerResult<()> {
+ Err(DemuxerError::NotPossible)
}
}
+impl<'a> NAOptionHandler for VMDDemuxer<'a> {
+ fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+ fn set_options(&mut self, _options: &[NAOption]) { }
+ fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
impl<'a> VMDDemuxer<'a> {
fn new(io: &'a mut ByteReader<'a>) -> Self {
Self {
aud_id: 0,
fno: 0,
is_indeo: false,
+ is_lhaud: false,
frames: Vec::new(),
}
}
pub struct VMDDemuxerCreator { }
impl DemuxerCreator for VMDDemuxerCreator {
- fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<DemuxCore<'a> + 'a> {
+ fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
Box::new(VMDDemuxer::new(br))
}
fn get_name(&self) -> &'static str { "vmd" }
#[test]
fn test_vmd_demux() {
- let mut file = File::open("assets/128.vmd").unwrap();
- //let mut file = File::open("assets/1491.VMD").unwrap();
+ let mut file = File::open("assets/Game/128.vmd").unwrap();
+ //let mut file = File::open("assets/Game/1491.VMD").unwrap();
let mut fr = FileReader::new_read(&mut file);
let mut br = ByteReader::new(&mut fr);
let mut dmx = VMDDemuxer::new(&mut br);
let mut sm = StreamManager::new();
- dmx.open(&mut sm).unwrap();
+ let mut si = SeekIndex::new();
+ dmx.open(&mut sm, &mut si).unwrap();
loop {
let pktres = dmx.get_frame(&mut sm);
if let Err(e) = pktres {