feat: add AdjustExistingTrackDrift use case to adjust drift scale of existing tracks
- Implemented AdjustExistingTrackDrift struct with execute method to modify drift scale of existing tracks in a project. - Added tests for adjusting drift scale, handling non-existent track IDs, and invalid scale values. - Updated MediaTrackInfo and AudioTrack entities to include drift_scale field. - Enhanced Project entity with needs_mkvmerge method to determine if mkvmerge is required based on drift scale. - Integrated drift scale adjustments into existing track list UI, allowing users to modify drift values. - Updated various use cases and UI components to support drift scale functionality, including add audio/subtitle forms and batch processing. - Implemented mkvmerge availability check and integrated it into the application workflow for conditional processing.
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::SyncOffset;
|
||||
|
||||
/// Transformação temporal completa de uma faixa: deslocamento constante + fator de escala.
|
||||
///
|
||||
/// - `offset_ms`: deslocamento em milissegundos (mesmo semântico de `SyncOffset`).
|
||||
/// - `scale`: fator de escala temporal. `1.0` = identidade. `0.99983` ≈ correção 25 fps → 24 fps.
|
||||
///
|
||||
/// Quando `scale == 1.0`, o pipeline padrão FFmpeg é utilizado.
|
||||
/// Quando `scale != 1.0`, o projeto precisa passar pelo pipeline mkvmerge.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SyncTransform {
|
||||
pub offset_ms: i64,
|
||||
pub scale: f64,
|
||||
}
|
||||
|
||||
impl SyncTransform {
|
||||
/// Cria uma transformação com deslocamento e escala explícitos.
|
||||
pub fn new(offset_ms: i64, scale: f64) -> Self {
|
||||
SyncTransform { offset_ms, scale }
|
||||
}
|
||||
|
||||
/// Cria uma transformação a partir de um `SyncOffset` sem drift (escala = 1.0).
|
||||
pub fn from_offset(offset: SyncOffset) -> Self {
|
||||
SyncTransform {
|
||||
offset_ms: offset.as_ms(),
|
||||
scale: 1.0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Retorna `true` se o fator de escala difere de 1.0 por mais de 1e-9.
|
||||
pub fn has_drift(&self) -> bool {
|
||||
(self.scale - 1.0).abs() > 1e-9
|
||||
}
|
||||
|
||||
/// Retorna `true` se a transformação é identidade (offset == 0 e sem drift).
|
||||
pub fn is_identity(&self) -> bool {
|
||||
self.offset_ms == 0 && !self.has_drift()
|
||||
}
|
||||
|
||||
/// Converte para `SyncOffset` descartando a escala (compatibilidade com FFmpeg path).
|
||||
pub fn to_sync_offset(&self) -> SyncOffset {
|
||||
SyncOffset::from_ms(self.offset_ms)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SyncTransform {
|
||||
/// Identidade: sem deslocamento, sem drift.
|
||||
fn default() -> Self {
|
||||
SyncTransform {
|
||||
offset_ms: 0,
|
||||
scale: 1.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn default_e_identidade() {
|
||||
let t = SyncTransform::default();
|
||||
assert!(t.is_identity());
|
||||
assert!(!t.has_drift());
|
||||
assert_eq!(t.offset_ms, 0);
|
||||
assert_eq!(t.scale, 1.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn has_drift_false_scale_1() {
|
||||
let t = SyncTransform::new(500, 1.0);
|
||||
assert!(!t.has_drift());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn has_drift_true_scale_0_99983() {
|
||||
let t = SyncTransform::new(0, 0.99983);
|
||||
assert!(t.has_drift());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_offset_sem_drift() {
|
||||
let offset = SyncOffset::from_ms(1200);
|
||||
let t = SyncTransform::from_offset(offset);
|
||||
assert_eq!(t.offset_ms, 1200);
|
||||
assert!(!t.has_drift());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_sync_offset_descarta_escala() {
|
||||
let t = SyncTransform::new(-500, 0.99983);
|
||||
assert_eq!(t.to_sync_offset().as_ms(), -500);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user