Files
simple-multimidia-track-aud…/src/domain/value_objects/sync_transform.rs
T
Felipe 1ef47b3a07 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.
2026-03-01 12:01:39 -03:00

97 lines
2.7 KiB
Rust

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);
}
}