Box::new(EuclidDecoder::new())
}
+#[derive(Default)]
+struct EuclidPacketiser {
+ stream: Option<NAStreamRef>,
+ buf: Vec<u8>,
+ frameno: u32,
+}
+
+impl EuclidPacketiser {
+ fn new() -> Self { Self::default() }
+}
+
+impl NAPacketiser for EuclidPacketiser {
+ fn attach_stream(&mut self, stream: NAStreamRef) {
+ self.stream = Some(stream);
+ }
+ fn add_data(&mut self, src: &[u8]) -> bool {
+ self.buf.extend_from_slice(src);
+ false
+ }
+ fn parse_stream(&mut self, id: u32) -> DecoderResult<NAStreamRef> {
+ if let Some(ref stream) = self.stream {
+ let mut stream = NAStream::clone(stream);
+ stream.id = id;
+ Ok(stream.into_ref())
+ } else {
+ Err(DecoderError::MissingReference)
+ }
+ }
+ fn skip_junk(&mut self) -> DecoderResult<usize> {
+ Err(DecoderError::NotImplemented)
+ }
+ fn get_packet(&mut self, stream: NAStreamRef) -> DecoderResult<Option<NAPacket>> {
+ if !self.buf.is_empty() {
+ let mut data = Vec::new();
+ std::mem::swap(&mut data, &mut self.buf);
+ let ts = NATimeInfo::new(Some(u64::from(self.frameno)), None, None, stream.tb_num, stream.tb_den);
+ self.frameno += 1;
+ Ok(Some(NAPacket::new(stream, ts, false, data)))
+ } else {
+ Ok(None)
+ }
+ }
+ fn reset(&mut self) {
+ self.buf.clear();
+ }
+ fn bytes_left(&self) -> usize { self.buf.len() }
+}
+
+pub fn get_packetiser() -> Box<dyn NAPacketiser + Send> {
+ Box::new(EuclidPacketiser::new())
+}
+
#[cfg(test)]
mod test {
use nihav_core::codecs::RegisteredDecoders;
#[cfg(feature="decoder_rawaudio")]
PacketiserInfo { name: "arm_rawaudio", get_packetiser: rawaudio::get_packetiser },
+#[cfg(feature="decoder_euclid")]
+ PacketiserInfo { name: "euclid", get_packetiser: euclid::get_packetiser },
+
#[cfg(feature="packetiser_cinepak")]
PacketiserInfo { name: "cinepak", get_packetiser: wss_packetisers::get_packetiser_cinepak },
#[cfg(feature="packetiser_msvideo1")]
use nihav_core::demuxers::*;
+#[cfg(feature="demuxer_tca")]
+use super::tca::TCARawDemuxer;
+
const VIDEO_CODECS: &[(i32, &str)] = &[
( 1, "movinglines"),
( 2, "arm_rawvideo"),
(122, "escape122"),
(124, "escape124"),
(130, "escape130"),
+ (500, "euclid"),
(600, "msvideo1"),
(601, "msvideo1"),
(602, "cinepak"),
state: ReadState,
video_id: Option<usize>,
audio_ids: Vec<usize>,
+ #[cfg(feature="demuxer_tca")]
+ tca: Option<TCARawDemuxer>,
}
impl<'a> ARMovieDemuxer<'a> {
state: ReadState::None,
video_id: None,
audio_ids: Vec::new(),
+ #[cfg(feature="demuxer_tca")]
+ tca: None,
}
}
fn parse_catalogue(&mut self, offset: u32, num_chunks: usize, even_csize: usize, odd_csize: usize, aud_tracks: usize) -> DemuxerResult<()> {
self.parse_catalogue(cat_offset, num_chunks, even_chunk_size, odd_chunk_size, num_sound)?;
+ #[cfg(feature="demuxer_tca")]
+ if video_codec == 500 {
+ validate!(fps > 1.0e-4);
+ let mut tbase = fps;
+ let mut tb_num = 1;
+ while tbase.fract() > 1.0e-4 {
+ tb_num *= 10;
+ tbase *= 10.0;
+ }
+ let tb_den = tbase as u32;
+
+ self.src.seek(SeekFrom::Start(u64::from(self.chunk_offs[0].offset)))?;
+ let mut tca = TCARawDemuxer::default();
+ tca.open(self.src, strmgr, tb_num, tb_den)?;
+ self.tca = Some(tca);
+ return Ok(());
+ }
+
let mut stream_id = 0;
if video_codec > 0 {
let codec_name = if let Some(idx) = VIDEO_CODECS.iter().position(|&(id, _)| id == video_codec) {
}
fn get_data(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NARawData> {
+ #[cfg(feature="demuxer_tca")]
+ if let Some(ref mut tca) = self.tca {
+ return tca.get_frame(self.src, strmgr);
+ }
+
while self.cur_chunk < self.chunk_offs.len() {
let chunk = &self.chunk_offs[self.cur_chunk];
match self.state {
fn get_name(&self) -> &'static str { "tca" }
}
+#[derive(Default)]
+pub(crate) struct TCARawDemuxer {
+ data_end: u64,
+}
+
+impl TCARawDemuxer {
+ pub(crate) fn open(&mut self, src: &mut ByteReader, strmgr: &mut StreamManager, tb_num: u32, tb_den: u32) -> DemuxerResult<()> {
+ let start_pos = src.tell();
+ let tag = src.peek_tag()?;
+ let is_acef = &tag == b"ACEF";
+ let acef_size = if is_acef {
+ src.read_skip(4)?;
+ src.read_u32le()?
+ } else { 0 };
+ let size2 = src.read_u32le()?;
+ if is_acef {
+ validate!(acef_size > 0x44 && size2 + 8 <= acef_size);
+ }
+ self.data_end = start_pos + u64::from(size2 + 8);
+
+ src.read_skip(12)?;
+
+ const HDR_SIZE: usize = 0x30;
+
+ let mut hdr = vec![0; HDR_SIZE + 4];
+ write_u32le(&mut hdr, HDR_SIZE as u32 + 4)?;
+ src.read_buf(&mut hdr[4..])?;
+
+ let width = read_u32le(&hdr[8..])? as usize;
+ let height = read_u32le(&hdr[12..])? as usize;
+ validate!(width > 0 && height > 0);
+ validate!((width | height) & 1 == 0);
+
+ if is_acef {
+ let data_start = src.tell();
+
+ // scan tail for palette and such
+ if src.seek(SeekFrom::Start(start_pos + u64::from(acef_size))).is_ok() {
+ while let Ok(tag) = src.read_tag() {
+ let size = src.read_u32le()? as usize;
+ validate!(size >= 8);
+ if &tag == b"PALE" {
+ validate!((0x28..=0x428).contains(&size) && (size & 3) == 0);
+ src.read_skip(0x1C)?;
+ let nclrs = (size - 0x24) / 4;
+ hdr.resize(HDR_SIZE + 4 + 256 * 3, 0);
+ for _ in 0..nclrs {
+ let idx = usize::from(src.read_byte()?);
+ src.read_buf(&mut hdr[HDR_SIZE + 4 + idx * 3..][..3])?;
+ }
+ } else {
+ src.read_skip(size - 8)?;
+ }
+ }
+ }
+ src.seek(SeekFrom::Start(data_start))?;
+ }
+
+ let vci = NACodecTypeInfo::Video(NAVideoInfo::new(width / 2, height / 2, false, PAL8_FORMAT));
+ let vinfo = NACodecInfo::new("euclid", vci, Some(hdr));
+ let ret = strmgr.add_stream(NAStream::new(StreamType::Video, 0, vinfo, tb_num, tb_den, 0));
+ if ret.is_none() {
+ return Err(DemuxerError::MemoryError);
+ }
+
+ Ok(())
+ }
+
+ pub(crate) fn get_frame(&mut self, src: &mut ByteReader, strmgr: &mut StreamManager) -> DemuxerResult<NARawData> {
+ if src.tell() >= self.data_end {
+ return Err(DemuxerError::EOF);
+ }
+ let fsize = src.read_u32le()? as usize;
+ if fsize == 0 {
+ return Err(DemuxerError::EOF);
+ }
+ validate!((9..=1048576).contains(&fsize));
+ if let Some(stream) = strmgr.get_stream(0) {
+ let mut buf = vec![0; fsize - 4];
+ src.read_buf(&mut buf)?;
+ Ok(NARawData::new(stream, buf))
+ } else {
+ Err(DemuxerError::InvalidData)
+ }
+ }
+}
+
#[cfg(test)]
mod test {
use super::*;