Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/container/mp4_container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ impl<R: Read + Seek> Mp4Container<R> {
}
}

impl<R: Read + Seek + 'static> ContainerReader for Mp4Container<R> {
impl<R: Read + Seek> ContainerReader for Mp4Container<R> {
fn read_info(&mut self) -> Result<ContainerInfo, String> {
self.parse()?;

Expand Down Expand Up @@ -973,3 +973,9 @@ impl Mp4Container<Cursor<Vec<u8>>> {
Self::new(Cursor::new(data))
}
}

impl<'a> Mp4Container<Cursor<&'a [u8]>> {
pub fn from_slice(data: &'a [u8]) -> Self {
Self::new(Cursor::new(data))
}
}
8 changes: 3 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,8 @@ pub fn get_gop_tags(result_json: &str, gop_index: usize) -> Result<JsValue, JsEr
pub fn parse_mp4(data: &[u8]) -> Result<JsValue, JsError> {
use container::{ContainerReader, Mp4Container};

let data_vec = data.to_vec();
let file_size = data_vec.len() as u64;
let mut container = Mp4Container::from_bytes(data_vec);
let file_size = data.len() as u64;
let mut container = Mp4Container::from_slice(data);

// 读取容器信息
let info = container.read_info().map_err(|e| JsError::new(&e))?;
Expand Down Expand Up @@ -394,8 +393,7 @@ pub fn get_mp4_sample_detail(
.ok_or_else(|| JsError::new("不是 MP4 Sample"))?;

// 重新解析 MP4 以获取详细信息
let data_vec = file_data.to_vec();
let mut container = Mp4Container::from_bytes(data_vec.clone());
let mut container = Mp4Container::from_slice(file_data);
let _info = container.read_info().map_err(|e| JsError::new(&e))?;

// 收集 sample 的详细信息
Expand Down
44 changes: 44 additions & 0 deletions tests/perf_benchmark.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use video_analyzer::container::{Mp4Container, ContainerReader};
use std::time::Instant;

fn generate_data(size: usize) -> Vec<u8> {
vec![0u8; size]
}

#[test]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To avoid running this performance benchmark on every cargo test (which can be slow), it's a good practice to add the #[ignore] attribute. This way, it will only run when explicitly requested with cargo test -- --ignored.

This helps separate long-running performance tests from regular unit tests.

#[test]
#[ignore]

#[ignore]
fn benchmark_allocation() {
let size = 50 * 1024 * 1024; // 50MB
let data = generate_data(size);
let data_slice = &data[..];

println!("Benchmarking with {} MB data...", size / 1024 / 1024);

// Baseline: Allocation (Old way)
let start = Instant::now();
for _ in 0..10 {
let data_vec = data_slice.to_vec();
let _container = Mp4Container::from_bytes(data_vec);
}
let duration_baseline = start.elapsed();
println!("Baseline (to_vec) (10 iterations): {:?}", duration_baseline);
println!("Baseline average: {:?}", duration_baseline / 10);

// Optimized: No allocation (New way)
let start = Instant::now();
for _ in 0..10 {
let _container = Mp4Container::from_slice(data_slice);
}
let duration_optimized = start.elapsed();
println!("Optimized (from_slice) (10 iterations): {:?}", duration_optimized);
println!("Optimized average: {:?}", duration_optimized / 10);

if duration_optimized < duration_baseline {
println!("Improvement: {:.2}x faster", duration_baseline.as_nanos() as f64 / duration_optimized.as_nanos() as f64);
}

// Verify trait usage compiles
let mut container = Mp4Container::from_slice(data_slice);
// This will error at runtime (invalid mp4), but compiles, proving the optimization works for the intended use case.
let _ = container.read_info();
}