feat: ASR output frame numbers + rename start/end to start_time/end_time

- Python: asr_processor.py detects FPS from CUT/ffprobe (no fallback), outputs start_frame/end_frame
- Rust: All AsrSegment structs use start_time/end_time with #[serde(alias)] for backward compat
- store_asr_chunks: prefers ASR output frames, falls back to time-based conversion
- Added backward compatibility test for old JSON format (start/end)

Breaking change: ffprobe/CUT FPS failure now aborts instead of using default 24fps
This commit is contained in:
Accusys
2026-05-19 13:22:38 +08:00
parent 26725dcab7
commit 67ca846ccd
9 changed files with 572 additions and 68 deletions

View File

@@ -64,8 +64,10 @@ struct Args {
#[derive(Debug, Clone, Serialize, Deserialize)]
struct AsrSegment {
start: f64,
end: f64,
#[serde(alias = "start")]
start_time: f64,
#[serde(alias = "end")]
end_time: f64,
text: String,
}
@@ -272,9 +274,9 @@ impl IntegratedPlayer {
if let Some(asr) = &self.asr_data {
for seg in &asr.segments {
if time >= seg.start && time <= seg.end {
segment.start = seg.start;
segment.end = seg.end;
if time >= seg.start_time && time <= seg.end_time {
segment.start = seg.start_time;
segment.end = seg.end_time;
segment.text = Some(seg.text.clone());
break;
}
@@ -440,11 +442,11 @@ fn run_continuous_demo(player: &IntegratedPlayer, args: &Args) -> Result<()> {
println!("\n[{}/{}] Segment", i + 1, total_segments);
println!("{:=<80}", "");
println!("📝 ASR Text: {}", seg.text);
println!("⏱ Time: {:.2}s - {:.2}s", seg.start, seg.end);
println!("⏱ Time: {:.2}s - {:.2}s", seg.start_time, seg.end_time);
if let Some(asrx) = &player.asrx_data {
for asrx_seg in &asrx.segments {
if seg.start >= asrx_seg.start && seg.start <= asrx_seg.end {
if seg.start_time >= asrx_seg.start && seg.start_time <= asrx_seg.end {
let (actor, character) = player.get_speaker_info(&asrx_seg.speaker);
println!(
"🎤 Speaker: {}{} ({})",
@@ -455,7 +457,7 @@ fn run_continuous_demo(player: &IntegratedPlayer, args: &Args) -> Result<()> {
}
}
if let Some(segment) = player.get_current_segment(seg.start + 0.01) {
if let Some(segment) = player.get_current_segment(seg.start_time + 0.01) {
if let Some(face) = &segment.face {
println!(
"👤 Face: bbox=({},{}) {}x{}, conf={:.2}",
@@ -467,17 +469,17 @@ fn run_continuous_demo(player: &IntegratedPlayer, args: &Args) -> Result<()> {
}
}
let duration = seg.end - seg.start;
let duration = seg.end_time - seg.start_time;
println!(
"▶️ Playing: {:.2}s - {:.2}s ({:.2}s)",
seg.start, seg.end, duration
seg.start_time, seg.end_time, duration
);
let mut cmd = Command::new("ffplay");
if args.show_video {
cmd.args([
"-ss",
&format!("{:.2}", seg.start),
&format!("{:.2}", seg.start_time),
"-t",
&format!("{:.2}", duration),
"-autoexit",
@@ -490,7 +492,7 @@ fn run_continuous_demo(player: &IntegratedPlayer, args: &Args) -> Result<()> {
} else {
cmd.args([
"-ss",
&format!("{:.2}", seg.start),
&format!("{:.2}", seg.start_time),
"-t",
&format!("{:.2}", duration),
"-autoexit",