#[macro_use] extern crate criterion; #[macro_use] extern crate mpeg2ts_reader; use criterion::{Criterion, Throughput}; use mpeg2ts_reader::demultiplex; use mpeg2ts_reader::pes; use mpeg2ts_reader::psi; use std::fs::File; use std::io::Read; packet_filter_switch! { NullFilterSwitch { Pat: demultiplex::PatPacketFilter, Pmt: demultiplex::PmtPacketFilter, Null: demultiplex::NullPacketFilter, NullPes: pes::PesPacketFilter, } } demux_context!(NullDemuxContext, NullFilterSwitch); impl NullDemuxContext { fn do_construct(&mut self, req: demultiplex::FilterRequest<'_, '_>) -> NullFilterSwitch { match req { demultiplex::FilterRequest::ByPid(psi::pat::PAT_PID) => { NullFilterSwitch::Pat(demultiplex::PatPacketFilter::default()) } demultiplex::FilterRequest::ByPid(_) => { NullFilterSwitch::Null(demultiplex::NullPacketFilter::default()) } demultiplex::FilterRequest::ByStream { pmt, stream_info, .. } => NullElementaryStreamConsumer::construct(pmt, stream_info), demultiplex::FilterRequest::Pmt { pid, program_number, } => NullFilterSwitch::Pmt(demultiplex::PmtPacketFilter::new(pid, program_number)), demultiplex::FilterRequest::Nit { .. } => { NullFilterSwitch::Null(demultiplex::NullPacketFilter::default()) } } } } pub struct NullElementaryStreamConsumer {} impl NullElementaryStreamConsumer { fn construct( _pmt_sect: &psi::pmt::PmtSection, stream_info: &psi::pmt::StreamInfo, ) -> NullFilterSwitch { println!("stream info: {:?}", stream_info); let filter = pes::PesPacketFilter::new(NullElementaryStreamConsumer {}); NullFilterSwitch::NullPes(filter) } } impl pes::ElementaryStreamConsumer for NullElementaryStreamConsumer { fn start_stream(&mut self, _ctx: &mut Ctx) {} fn begin_packet(&mut self, _ctx: &mut Ctx, header: pes::PesHeader) { if let pes::PesContents::Parsed(Some(content)) = header.contents() { match content.pts_dts() { Ok(pes::PtsDts::PtsOnly(Ok(ts))) => { criterion::black_box(ts); } Ok(pes::PtsDts::Both { pts: Ok(ts), .. }) => { criterion::black_box(ts); } _ => (), }; } } fn continue_packet(&mut self, _ctx: &mut Ctx, _data: &[u8]) {} fn end_packet(&mut self, _ctx: &mut Ctx) {} fn continuity_error(&mut self, _ctx: &mut Ctx) {} } fn mpeg2ts_reader(c: &mut Criterion) { let buf = if std::env::var("GITHUB_ACTIONS").is_ok() || std::env::var("GIT_AUTHOR_DATE").is_ok() { // HACK // we don't run benchmarking on github, or in pre-commit hook, but we do test that the // benchmark code executes without errors, so we need an input buffer of some kind for the // code to consume vec![0; 188] } else { let mut f = File::open("testsrc.ts") .expect("Test file missing. To create, run: mkdir -p resources && ffmpeg -f lavfi -i testsrc=duration=20:size=640x360:rate=30,noise=alls=20:allf=t+u -f lavfi -i sine=duration=20:frequency=1:beep_factor=480:sample_rate=48000 -c:v libx264 -b:v 20M -map 0:v -c:a aac -b:a 128k -map 1:a -vf format=yuv420p -f mpegts testsrc.ts"); let l = f.metadata().unwrap().len() as usize; let size = l.min(188 * 200_000); let mut buf = vec![0; size]; f.read(&mut buf[..]).unwrap(); buf }; let mut ctx = NullDemuxContext::new(); let mut demux = demultiplex::Demultiplex::new(&mut ctx); let mut group = c.benchmark_group("parse"); group.throughput(Throughput::Bytes(buf.len() as _)); group.bench_function("parse", move |b| { b.iter(|| demux.push(&mut ctx, &buf[..])); }); group.finish(); } criterion_group!(benches, mpeg2ts_reader); criterion_main!(benches);