--- /dev/null
+use super::*;
+use io::byteio::*;
+use frame::*;
+use std::io::SeekFrom;
+//use std::collections::HashMap;
+
+enum GDVState {
+ NewFrame,
+ AudioRead,
+}
+
+#[allow(dead_code)]
+pub struct GremlinVideoDemuxer<'a> {
+ opened: bool,
+ src: &'a mut ByteReader<'a>,
+ streams: Vec<Rc<NAStream<'a>>>,
+ frames: u16,
+ cur_frame: u16,
+ asize: usize,
+ apacked: bool,
+ state: GDVState,
+ pktdta: Vec<u8>,
+}
+
+impl<'a> NADemuxer<'a> for GremlinVideoDemuxer<'a> {
+ #[allow(unused_variables)]
+ fn open(&mut self) -> DemuxerResult<()> {
+ let src = &mut self.src;
+ let magic = src.read_u32le()?;
+ if magic != 0x29111994 { return Err(DemuxerError::InvalidData); }
+ let id = src.read_u16le()?;
+ let frames = src.read_u16le()?;
+ let fps = src.read_u16le()?;
+ let aflags = src.read_u16le()?;
+ let rate = src.read_u16le()?;
+ let depth = src.read_u16le()?;
+ let max_fs = src.read_u16le()?;
+ src.read_skip(2)?;
+ let width = src.read_u16le()?;
+ let height = src.read_u16le()?;
+println!("id {} frames {} fps {} sound {} Hz {:X} img {} - {}x{}",id,frames,fps,rate,aflags,depth,width,height);
+ if max_fs > 0 {
+ let vhdr = NAVideoInfo::new(width as u32, height as u32, false, PAL8_FORMAT);
+ let vci = NACodecTypeInfo::Video(vhdr);
+ let vinfo = NACodecInfo::new(vci, None);
+ let vstr = NAStream::new(StreamType::Video, 0, vinfo);
+ self.streams.push(Rc::new(vstr));
+ }
+ if (aflags & 1) != 0 {
+ let channels = if (aflags & 2) != 0 { 2 } else { 1 };
+ let ahdr = NAAudioInfo::new(rate as u32, channels as u8, if (aflags & 4) != 0 { SND_S16_FORMAT } else { SND_U8_FORMAT }, 2);
+ let ainfo = NACodecInfo::new(NACodecTypeInfo::Audio(ahdr), None);
+ let astr = NAStream::new(StreamType::Audio, 1, ainfo);
+ self.streams.push(Rc::new(astr));
+
+ let packed = if (aflags & 8) != 0 { 1 } else { 0 };
+ self.asize = (((rate / fps) * channels * (if (aflags & 4) != 0 { 2 } else { 1 })) >> packed) as usize;
+ self.apacked = (aflags & 8) != 0;
+println!("audio chunk size {}({:X})",self.asize,self.asize);
+ }
+ if max_fs > 0 && depth == 1 {
+ src.read_skip(768)?;
+ }
+ self.frames = frames;
+ self.opened = true;
+ self.state = GDVState::NewFrame;
+ Ok(())
+ }
+
+ #[allow(unused_variables)]
+ fn get_frame(&mut self) -> DemuxerResult<NAPacket> {
+ if !self.opened { return Err(DemuxerError::NoSuchInput); }
+ if self.cur_frame >= self.frames { return Err(DemuxerError::EOF); }
+ match self.state {
+ GDVState::NewFrame if self.asize > 0 => { self.read_achunk() }
+ _ => { self.read_vchunk() }
+ }
+ }
+
+ #[allow(unused_variables)]
+ fn seek(&mut self, time: u64) -> DemuxerResult<()> {
+ if !self.opened { return Err(DemuxerError::NoSuchInput); }
+ Err(DemuxerError::NotImplemented)
+ }
+}
+/*impl<'a> Drop for GremlinVideoDemuxer<'a> {
+ #[allow(unused_variables)]
+ fn drop(&mut self) {
+ }
+}*/
+impl<'a> GremlinVideoDemuxer<'a> {
+ pub fn new(io: &'a mut ByteReader<'a>) -> Self {
+ GremlinVideoDemuxer {
+ cur_frame: 0,
+ frames: 0,
+ opened: false,
+ asize: 0,
+ apacked: false,
+ state: GDVState::NewFrame,
+pktdta: Vec::new(),
+ src: io,
+ streams: Vec::new()
+ }
+ }
+
+ fn find_stream(&mut self, id: u32) -> Rc<NAStream<'a>> {
+ for i in 0..self.streams.len() {
+ if self.streams[i].get_id() == id {
+ return self.streams[i].clone();
+ }
+ }
+ panic!("stream not found");
+ }
+ fn read_achunk(&mut self) -> DemuxerResult<NAPacket> {
+ self.state = GDVState::AudioRead;
+ let str = self.find_stream(1);
+ self.src.read_packet(str, Some(self.cur_frame as u64), None, None, true, self.asize)
+ }
+
+ fn read_vchunk(&mut self) -> DemuxerResult<NAPacket> {
+ let str = self.find_stream(0);
+ let mut src = &mut self.src;
+ let magic = src.read_u16be()?;
+ if magic != 0x0513 { return Err(DemuxerError::InvalidData); }
+ let size = (src.read_u16le()? as usize) + 4;
+ let tmp = src.read_u32le()?;
+ let flags = (tmp & 0xFF) as usize;
+ src.seek(SeekFrom::Current(-4))?;
+ self.state = GDVState::NewFrame;
+ self.cur_frame = self.cur_frame + 1;
+ src.read_packet(str, Some((self.cur_frame - 1) as u64), None, None, if (flags & 64) != 0 { true } else { false }, size)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use std::fs::File;
+
+ #[test]
+ fn test_gdv_demux() {
+ let mut file = File::open("assets/intro1.gdv").unwrap();
+ let mut fr = FileReader::new_read(&mut file);
+ let mut br = ByteReader::new(&mut fr);
+ let mut dmx = GremlinVideoDemuxer::new(&mut br);
+ dmx.open().unwrap();
+ loop {
+ let pktres = dmx.get_frame();
+ if let Err(e) = pktres {
+ if (e as i32) == (DemuxerError::EOF as i32) { break; }
+ panic!("error");
+ }
+ let pkt = pktres.unwrap();
+ println!("Got {}", pkt);
+ }
+ }
+}
--- /dev/null
+pub mod gdv;
+
+use std::fmt;
+use std::rc::Rc;
+use frame::*;
+//use std::collections::HashMap;
+use io::byteio::*;
+
+#[derive(Debug)]
+#[allow(dead_code)]
+pub enum StreamType {
+ Video,
+ Audio,
+ Subtitles,
+ Data,
+}
+
+impl fmt::Display for StreamType {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ StreamType::Video => write!(f, "Video"),
+ StreamType::Audio => write!(f, "Audio"),
+ StreamType::Subtitles => write!(f, "Subtitles"),
+ StreamType::Data => write!(f, "Data"),
+ }
+ }
+}
+
+
+#[allow(dead_code)]
+pub struct NAStream<'a> {
+ media_type: StreamType,
+ id: u32,
+ info: Rc<NACodecInfo<'a>>,
+}
+
+impl<'a> NAStream<'a> {
+ pub fn new(mt: StreamType, id: u32, info: NACodecInfo<'a>) -> Self {
+ NAStream { media_type: mt, id: id, info: Rc::new(info) }
+ }
+ pub fn get_id(&self) -> u32 { self.id }
+ pub fn get_info(&self) -> Rc<NACodecInfo<'a>> { self.info.clone() }
+}
+
+impl<'a> fmt::Display for NAStream<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "({}#{})", self.media_type, self.id)
+ }
+}
+
+#[allow(dead_code)]
+pub struct NAPacket<'a> {
+ stream: Rc<NAStream<'a>>,
+ pts: Option<u64>,
+ dts: Option<u64>,
+ duration: Option<u64>,
+ buffer: Rc<Vec<u8>>,
+ keyframe: bool,
+// options: HashMap<String, NAValue<'a>>,
+}
+
+impl<'a> NAPacket<'a> {
+ pub fn new(str: Rc<NAStream<'a>>, pts: Option<u64>, dts: Option<u64>, dur: Option<u64>, kf: bool, vec: Vec<u8>) -> Self {
+// let mut vec: Vec<u8> = Vec::new();
+// vec.resize(size, 0);
+ NAPacket { stream: str, pts: pts, dts: dts, duration: dur, keyframe: kf, buffer: Rc::new(vec) }
+ }
+ pub fn get_stream(&self) -> Rc<NAStream<'a>> { self.stream.clone() }
+ pub fn get_pts(&self) -> Option<u64> { self.pts }
+ pub fn get_buffer(&self) -> Rc<Vec<u8>> { self.buffer.clone() }
+}
+
+impl<'a> fmt::Display for NAPacket<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut foo = format!("[pkt for {} size {}", self.stream, self.buffer.len());
+ if let Some(pts) = self.pts { foo = format!("{} pts {}", foo, pts); }
+ if let Some(dts) = self.dts { foo = format!("{} dts {}", foo, dts); }
+ if let Some(dur) = self.duration { foo = format!("{} duration {}", foo, dur); }
+ if self.keyframe { foo = format!("{} kf", foo); }
+ foo = foo + "]";
+ write!(f, "{}", foo)
+ }
+}
+
+#[derive(Debug)]
+#[allow(dead_code)]
+pub enum DemuxerError {
+ EOF,
+ NoSuchInput,
+ InvalidData,
+ IOError,
+ NotImplemented,
+ MemoryError,
+}
+
+type DemuxerResult<T> = Result<T, DemuxerError>;
+
+pub trait NADemuxer<'a> {
+ fn open(&mut self) -> DemuxerResult<()>;
+ fn get_frame(&mut self) -> DemuxerResult<NAPacket>;
+ fn seek(&mut self, time: u64) -> DemuxerResult<()>;
+}
+
+pub trait NAPacketReader<'a> {
+ fn read_packet(&mut self, str: Rc<NAStream<'a>>, pts: Option<u64>, dts: Option<u64>, dur: Option<u64>, keyframe: bool, size: usize) -> DemuxerResult<NAPacket>;
+ fn fill_packet(&mut self, pkt: &mut NAPacket) -> DemuxerResult<()>;
+}
+
+impl<'a> NAPacketReader<'a> for ByteReader<'a> {
+ fn read_packet(&mut self, str: Rc<NAStream<'a>>, pts: Option<u64>, dts: Option<u64>, dur: Option<u64>, kf: bool, size: usize) -> DemuxerResult<NAPacket> {
+ let mut buf: Vec<u8> = Vec::with_capacity(size);
+ if buf.capacity() < size { return Err(DemuxerError::MemoryError); }
+ buf.resize(size, 0);
+ let res = self.read_buf(buf.as_mut_slice());
+ if let Err(_) = res { return Err(DemuxerError::IOError); }
+ if res.unwrap() < buf.len() { return Err(DemuxerError::IOError); }
+ let pkt = NAPacket::new(str, pts, dts, dur, kf, buf);
+ Ok(pkt)
+ }
+ fn fill_packet(&mut self, pkt: &mut NAPacket) -> DemuxerResult<()> {
+ let mut refbuf = pkt.get_buffer();
+ let mut buf = Rc::make_mut(&mut refbuf);
+ let res = self.read_buf(buf.as_mut_slice());
+ if let Err(_) = res { return Err(DemuxerError::IOError); }
+ if res.unwrap() < buf.len() { return Err(DemuxerError::IOError); }
+ Ok(())
+ }
+}
+
+pub struct NADemuxerBuilder {
+}
+
+impl From<ByteIOError> for DemuxerError {
+ fn from(_: ByteIOError) -> Self { DemuxerError::IOError }
+}
+
+impl NADemuxerBuilder {
+ #[allow(unused_variables)]
+ pub fn create_demuxer(name: &str, url: &str) -> DemuxerResult<Box<NADemuxer<'static>>> {
+ unimplemented!()
+ }
+}
--- /dev/null
+use std::collections::HashMap;
+
+#[allow(dead_code)]
+pub struct NASoniton {
+ bits: u8,
+ is_be: bool,
+ packed: bool,
+ planar: bool,
+ float: bool,
+}
+
+#[allow(dead_code)]
+pub const SND_U8_FORMAT: NASoniton = NASoniton { bits: 8, is_be: false, packed: false, planar: false, float: false };
+#[allow(dead_code)]
+pub const SND_S16_FORMAT: NASoniton = NASoniton { bits: 16, is_be: false, packed: false, planar: false, float: false };
+
+#[allow(dead_code)]
+pub struct NAAudioInfo {
+ sample_rate: u32,
+ channels: u8,
+ format: NASoniton,
+ block_len: usize,
+}
+
+impl NAAudioInfo {
+ pub fn new(sr: u32, ch: u8, fmt: NASoniton, bl: usize) -> Self {
+ NAAudioInfo { sample_rate: sr, channels: ch, format: fmt, block_len: bl }
+ }
+}
+
+#[derive(Debug)]
+pub enum ColorModel {
+ RGB,
+ YUV,
+ CMYK,
+ HSV,
+ LAB,
+}
+
+#[allow(dead_code)]
+pub struct NAPixelChromaton {
+ h_ss: u8,
+ v_ss: u8,
+ is_packed: bool,
+ depth: u8,
+ shift: u8,
+ comp_offs: u8,
+ next_elem: u8,
+}
+
+#[allow(dead_code)]
+pub struct NAPixelFormaton {
+ model: ColorModel,
+ components: u8,
+ comp_info: [Option<NAPixelChromaton>; 5],
+ elem_size: u8,
+ has_alpha: bool,
+ is_palette: bool,
+}
+
+macro_rules! chromaton {
+ ($hs: expr, $vs: expr, $pck: expr, $d: expr, $sh: expr, $co: expr, $ne: expr) => ({
+ Some(NAPixelChromaton{ h_ss: $hs, v_ss: $vs, is_packed: $pck, depth: $d, shift: $sh, comp_offs: $co, next_elem: $ne })
+ });
+ (yuv8; $hs: expr, $vs: expr, $co: expr) => ({
+ Some(NAPixelChromaton{ h_ss: $hs, v_ss: $vs, is_packed: false, depth: 8, shift: 0, comp_offs: $co, next_elem: 1 })
+ });
+ (pal8; $co: expr) => ({
+ Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, is_packed: true, depth: 8, shift: 0, comp_offs: $co, next_elem: 3 })
+ });
+}
+
+#[allow(dead_code)]
+pub const YUV420_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::YUV, components: 3,
+ comp_info: [
+ chromaton!(0, 0, false, 8, 0, 0, 1),
+ chromaton!(yuv8; 1, 1, 1),
+ chromaton!(yuv8; 1, 1, 2),
+ None, None],
+ elem_size: 0, has_alpha: false, is_palette: false };
+
+#[allow(dead_code)]
+pub const PAL8_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::RGB, components: 3,
+ comp_info: [
+ chromaton!(pal8; 0),
+ chromaton!(pal8; 1),
+ chromaton!(pal8; 2),
+ None, None],
+ elem_size: 1, has_alpha: false, is_palette: true };
+
+
+#[allow(dead_code)]
+pub struct NAVideoInfo {
+ width: u32,
+ height: u32,
+ flipped: bool,
+ format: NAPixelFormaton,
+}
+
+impl NAVideoInfo {
+ pub fn new(w: u32, h: u32, flip: bool, fmt: NAPixelFormaton) -> Self {
+ NAVideoInfo { width: w, height: h, flipped: flip, format: fmt }
+ }
+}
+
+pub enum NACodecTypeInfo {
+ None,
+ Audio(NAAudioInfo),
+ Video(NAVideoInfo),
+}
+
+#[allow(dead_code)]
+pub struct NABuffer<'a> {
+ id: u64,
+ data: &'a mut [u8],
+}
+
+#[allow(dead_code)]
+pub struct NACodecInfo<'a> {
+ properties: NACodecTypeInfo,
+ extradata: Option<&'a[u8]>,
+}
+
+impl<'a> NACodecInfo<'a> {
+ pub fn new(p: NACodecTypeInfo, edata: Option<&'a[u8]>) -> Self {
+ NACodecInfo { properties: p, extradata: edata }
+ }
+}
+
+pub trait NABufferAllocator {
+ fn alloc_buf(info: &NACodecInfo) -> NABuffer<'static>;
+}
+
+#[derive(Debug)]
+pub enum NAValue<'a> {
+ None,
+ Int(i32),
+ Long(i64),
+ String(String),
+ Data(&'a [u8]),
+}
+
+#[allow(dead_code)]
+pub struct NAFrame<'a> {
+ pts: Option<u64>,
+ dts: Option<u64>,
+ duration: Option<u64>,
+ buffer: &'a mut NABuffer<'a>,
+ info: &'a NACodecInfo<'a>,
+ options: HashMap<String, NAValue<'a>>,
+}
+
+#[allow(dead_code)]
+pub struct NACodecContext<'a> {
+ info: &'a NACodecInfo<'a>,
+}
+pub mod demuxers;
+pub mod frame;
pub mod io;