use std::io;
mod fmp4_processor;
mod mp4_parser;
mod mp4_writer;
mod thumbnail;
mod ts_parser;
pub use thumbnail::{extract_thumbnail_from_mp4, extract_thumbnail_from_ts};
pub use mp4_parser::{defragment_mp4, reset_mp4_timestamps};
pub use fmp4_processor::FragmentedMP4Processor;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn convert_ts_to_mp4_wasm(ts_data: &[u8]) -> Result<Vec<u8>, JsValue> {
convert_ts_to_mp4(ts_data).map_err(|e| JsValue::from_str(&format!("Conversion error: {}", e)))
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn convert_ts_to_mp4_reset_timestamps_wasm(ts_data: &[u8]) -> Result<Vec<u8>, JsValue> {
convert_ts_to_mp4_with_options(ts_data, true)
.map_err(|e| JsValue::from_str(&format!("Conversion error: {}", e)))
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn reset_mp4_timestamps_wasm(mp4_data: &[u8]) -> Result<Vec<u8>, JsValue> {
reset_mp4_timestamps(mp4_data)
.map_err(|e| JsValue::from_str(&format!("Timestamp reset error: {}", e)))
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn defragment_mp4_wasm(mp4_data: &[u8]) -> Result<Vec<u8>, JsValue> {
defragment_mp4(mp4_data).map_err(|e| JsValue::from_str(&format!("Defragment error: {}", e)))
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn convert_mp4_reset_timestamps_wasm(mp4_data: &[u8]) -> Result<Vec<u8>, JsValue> {
convert_mp4_reset_timestamps(mp4_data)
.map_err(|e| JsValue::from_str(&format!("Convert MP4 error: {}", e)))
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn extract_thumbnail_from_ts_wasm(ts_data: &[u8]) -> Result<Vec<u8>, JsValue> {
extract_thumbnail_from_ts(ts_data)
.map_err(|e| JsValue::from_str(&format!("Thumbnail extraction error: {}", e)))
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn extract_thumbnail_from_mp4_wasm(mp4_data: &[u8]) -> Result<Vec<u8>, JsValue> {
extract_thumbnail_from_mp4(mp4_data)
.map_err(|e| JsValue::from_str(&format!("Thumbnail extraction error: {}", e)))
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub struct FragmentedMP4ProcessorWasm {
processor: FragmentedMP4Processor,
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
impl FragmentedMP4ProcessorWasm {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
Self {
processor: FragmentedMP4Processor::new(),
}
}
#[wasm_bindgen]
pub fn set_init_segment(&mut self, data: &[u8]) -> Result<(), JsValue> {
self.processor
.set_init_segment(data)
.map_err(|e| JsValue::from_str(&format!("Init segment error: {}", e)))
}
#[wasm_bindgen]
pub fn process_segment(&mut self, data: &[u8]) -> Result<Vec<u8>, JsValue> {
self.processor
.process_segment(data)
.map_err(|e| JsValue::from_str(&format!("Segment processing error: {}", e)))
}
#[wasm_bindgen]
pub fn reset(&mut self) {
self.processor.reset();
}
#[wasm_bindgen]
pub fn get_base_decode_time(&self) -> Option<f64> {
self.processor.get_base_decode_time().map(|t| t as f64)
}
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn init_panic_hook() {
console_error_panic_hook::set_once();
}
pub fn convert_ts_to_mp4(ts_data: &[u8]) -> io::Result<Vec<u8>> {
convert_ts_to_mp4_with_options(ts_data, false)
}
pub fn convert_ts_to_mp4_with_options(
ts_data: &[u8],
reset_timestamps: bool,
) -> io::Result<Vec<u8>> {
let media_data = ts_parser::parse_ts_packets(ts_data)?;
let mp4_data = mp4_writer::create_mp4_with_options(media_data, reset_timestamps)?;
Ok(mp4_data)
}
pub fn convert_mp4_reset_timestamps(mp4_data: &[u8]) -> io::Result<Vec<u8>> {
match defragment_mp4(mp4_data) {
Ok(data) => {
Ok(data)
}
Err(_) => {
reset_mp4_timestamps(mp4_data)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_conversion() {
let ts_data = vec![0x47; 188]; let result = convert_ts_to_mp4(&ts_data);
assert!(result.is_err());
}
}