chore(i18n): finish translating code comments and scripts to English
CI / Format and clippy (push) Successful in 1m57s
CI / Dependency audit (push) Successful in 13s
CI / Check desktop app (Linux) (push) Successful in 3m54s
CI / Tests (Linux) (push) Failing after 7m25s
Release / Create release (push) Successful in 6s
Release / CLI (linux-aarch64) (push) Successful in 1m48s
Release / CLI (linux-x86_64) (push) Successful in 2m39s
Release / Desktop app (linux-aarch64) (push) Successful in 10m9s
Release / Desktop app (linux-x86_64) (push) Successful in 12m20s
Release / Desktop app (windows) (push) Successful in 7m32s
Release / Build latest.json (push) Successful in 5s

Completes the English-only standardization for code, comments, scripts
and CI templates (UI/CLI-facing strings stay bilingual pt-BR/en,
untouched). Covers the remaining crates/, apps/gui/ui/ and
apps/gui/src-tauri/ comments, .gitea/ workflow and template comments,
.githooks/ hooks, and the scripts/ source comments for the files
already renamed in a prior commit (check.sh, generate-logo.py,
install-hooks.sh).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
This commit is contained in:
Lucas RayanandClaude Sonnet 5 committed 2026-10-30 20:43:02 -03:00
1 parent da212e6926
commit 6328220c60
129 files changed
+1961 -1834

No files matched your search

+49 -49
View File
@@ -1,7 +1,7 @@
//! Reconstrução de vídeo MP4/MOV sem o átomo `moov` (gravação interrompida de câmera ou drone,
//! arquivo cortado). Os quadros ficam no `mdat` como unidades NAL com prefixo de tamanho; o
//! índice (`moov`) é refeito a partir delas: tamanhos de amostra, quadros-chave, tempo e, para
//! H.264, a ordem de apresentação (POC) quando há quadros B. O áudio não é reconstruído.
//! Reconstructs MP4/MOV video files missing their `moov` atom (interrupted camera/drone recordings
//! or truncated files). Video frames sit in `mdat` as length-prefixed NAL units; we rebuild the
//! `moov` index from them: sample sizes, keyframes, timing, and for H.264, presentation order
//! (POC) when B-frames are present. Audio tracks are not reconstructed.
use crate::source::{read_vec, Source};
@@ -58,7 +58,7 @@ impl<'a> Bits<'a> {
}
}
/// Remove os bytes de "emulation prevention" (00 00 03 -> 00 00).
/// Strips H.264/HEVC emulation prevention bytes (`00 00 03` -> `00 00`).
fn unescape(nal: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(nal.len());
let mut z = 0;
@@ -86,7 +86,7 @@ pub struct Sps264 {
pub poc_type: u32,
pub log2_max_poc_lsb: u32,
pub frame_mbs_only: bool,
/// (unidades por tique, escala de tempo)
/// `(num_units_in_tick, time_scale)` from VUI timing info.
pub timing: Option<(u32, u32)>,
}
@@ -173,7 +173,7 @@ pub fn parse_sps264(nal: &[u8]) -> Option<Sps264> {
};
s.width = (w * 16).checked_sub((cl + cr) * sub_w)?;
s.height = ((2 - s.frame_mbs_only as u32) * h * 16).checked_sub((ct + cb) * sub_h)?;
// VUI até o timing_info.
// Parse VUI parameters up to `timing_info_present_flag`.
if b.bit()? == 1 {
if b.bit()? == 1 && b.u(8)? == 255 {
b.skip(32);
@@ -202,7 +202,7 @@ pub fn parse_sps264(nal: &[u8]) -> Option<Sps264> {
Some(s)
}
/// (primeiro_mb == 0, tipo de fatia, pps_id, frame_num, idr, poc_lsb) do cabeçalho de fatia H.264.
/// Parses `(first_mb == 0, slice_type, pps_id, frame_num, is_idr, poc_lsb)` from an H.264 slice header.
struct SliceInfo {
frame_num: u32,
first_mb0: bool,
@@ -240,7 +240,7 @@ fn slice264(nal: &[u8], sps: &Sps264, pic_order_present: bool) -> Option<SliceIn
})
}
/// bottom_field_pic_order_in_frame_present_flag do PPS.
/// Extracts `bottom_field_pic_order_in_frame_present_flag` from an H.264 PPS.
fn pps_pic_order_present(nal: &[u8]) -> bool {
let rbsp = unescape(&nal[1..]);
let mut b = Bits::new(&rbsp);
@@ -278,7 +278,7 @@ pub fn parse_sps_hevc(nal: &[u8]) -> Option<SpsHevc> {
*v = b.u(8)? as u8;
let _ = i;
}
// general: 2+1+5 bits, 32 compat, 48 flags, 8 level => lemos 12 bytes (1+4+6+1)
// general profile/tier/level: 2+1+5 bits, 32 compat, 48 constraint flags, 8 level => 12 bytes (1+4+6+1)
let mut sub_profile = vec![];
let mut sub_level = vec![];
for _ in 0..max_sub {
@@ -320,9 +320,9 @@ pub fn parse_sps_hevc(nal: &[u8]) -> Option<SpsHevc> {
Some(s)
}
// -------------------------------------------------------------- amostras
// -------------------------------------------------------------- samples
/// Configuração de codec (SPS/PPS/VPS) extraída de um vídeo íntegro da mesma câmera.
/// Codec parameter sets (SPS/PPS/VPS) extracted from a donor video recorded by the same camera.
#[derive(Clone, Debug)]
pub struct MediaConfig {
pub codec: Codec,
@@ -331,9 +331,9 @@ pub struct MediaConfig {
pub vps: Vec<Vec<u8>>,
}
/// Procura o `avcC`/`hvcC` de um MP4 completo (lê até `max` bytes a partir de `off`).
/// Extracts `avcC`/`hvcC` codec configuration from an intact MP4 (reading up to `max` bytes from `off`).
pub fn config_from_mp4(src: &dyn Source, off: u64, max: u64) -> Option<MediaConfig> {
// O moov costuma estar no começo ou no fim: procura nos dois lugares.
// The `moov` atom is typically near the beginning or the end of the file: check both.
let size = src.size();
let head = read_vec(src, off, max.min(4 << 20) as usize).ok()?;
let mut hay: Vec<Vec<u8>> = vec![head];
@@ -416,7 +416,7 @@ pub enum Codec {
#[derive(Clone, Debug)]
struct Sample {
/// Posição absoluta (na origem) do primeiro byte da amostra (prefixo de tamanho incluso).
/// Absolute source offset of the first byte of the sample (including the 4-byte length prefix).
off: u64,
size: u32,
sync: bool,
@@ -425,9 +425,9 @@ struct Sample {
}
pub struct Rebuilt {
/// Bytes do arquivo original antes do `mdat` (ftyp etc.).
/// Leading atoms from the original file before `mdat` (`ftyp`, etc.).
pub pre_len: u64,
/// Onde começam e terminam os dados dos quadros na origem.
/// Start and end offsets of the video sample payload in the source.
pub payload: (u64, u64),
pub moov: Vec<u8>,
pub frames: usize,
@@ -439,7 +439,7 @@ pub struct Rebuilt {
}
impl Rebuilt {
/// Cabeçalho `mdat` de 64 bits para o payload.
/// 16-byte 64-bit `mdat` atom header covering the sample payload.
pub fn mdat_header(&self) -> Vec<u8> {
let size = 16 + (self.payload.1 - self.payload.0);
let mut v = Vec::with_capacity(16);
@@ -457,7 +457,7 @@ fn hevc_nal_ok(b0: u8, b1: u8) -> bool {
b0 & 0x81 == 0 && ((b0 >> 1) & 0x3F) <= 40 && b1 & 0x07 != 0 && (b1 >> 3) == 0
}
/// Cabeçalho do átomo `mdat` que começa em `at`: (início dos dados, tamanho declarado ou 0).
/// Parses the `mdat` header at `at`: returns `(payload_start, declared_end_or_0)`.
fn mdat_at(src: &dyn Source, at: u64) -> Option<(u64, u64)> {
let h = read_vec(src, at, 16).ok()?;
if h.len() < 8 || &h[4..8] != b"mdat" {
@@ -471,7 +471,7 @@ fn mdat_at(src: &dyn Source, at: u64) -> Option<(u64, u64)> {
}
}
/// Reconstrói o índice de um MP4 que começa em `off`, sem `moov`. `avail` limita a leitura.
/// Rebuilds the `moov` index for a headerless/truncated MP4 starting at `off` (reading at most `avail` bytes).
pub fn rebuild(src: &dyn Source, off: u64, avail: u64, refs: &[MediaConfig]) -> Option<Rebuilt> {
if let Some(r) = rebuild_with(src, off, avail, None) {
return Some(r);
@@ -486,7 +486,7 @@ fn rebuild_with(
avail: u64,
preset: Option<&MediaConfig>,
) -> Option<Rebuilt> {
// Átomos antes do mdat.
// Parse leading atoms before `mdat`.
let mut p = 0u64;
let mut pre_end = None;
for _ in 0..16 {
@@ -520,7 +520,7 @@ fn rebuild_with(
(off + pre_len + declared).min(hard_end)
};
// Lê o payload em blocos, interpretando NALs.
// Scan the `mdat` payload in chunks, parsing length-prefixed NAL units.
let mut samples: Vec<Sample> = vec![];
let mut cache: Vec<u8> = vec![];
let mut cache_off = data_start;
@@ -536,7 +536,7 @@ fn rebuild_with(
let s = (o - *cache_off) as usize;
cache.get(s..s + n).map(|x| x.to_vec())
};
// Detecta o codec: o que forma a cadeia mais longa de unidades NAL válidas.
// Detect the codec (H.264 vs HEVC) that yields the longest initial chain of valid NAL units.
let chain = |c: Codec| -> usize {
let Ok(head) = read_vec(src, data_start, 64 << 10) else {
return 0;
@@ -599,10 +599,10 @@ fn rebuild_with(
let mut idr_total = 0usize;
let mut idr_bad = 0usize;
let mut cur: Option<Sample> = None;
let mut group_start: Option<u64> = None; // início do grupo de NALs não-VCL que precede um quadro
let mut group_start: Option<u64> = None; // start offset of the non-VCL NAL group preceding a frame
let mut nal_count = 0usize;
let mut max_len = 0u64;
// POC (H.264, tipo 0)
// POC (H.264 pic_order_cnt_type 0)
let mut prev_msb: i64 = 0;
let mut prev_lsb: i64 = 0;
@@ -617,7 +617,7 @@ fn rebuild_with(
};
let mut ok = ok;
if ok && nal_count >= 3 && len > (max_len * 6).max(1 << 20) {
// Um "tamanho" muito maior que os já vistos é lixo (áudio lido como vídeo).
// A declared NAL length far larger than valid range is interleaved audio or garbage.
ok = false;
}
if ok {
@@ -629,7 +629,7 @@ fn rebuild_with(
max_len = max_len.max(len);
}
if !valid {
// Pode ser áudio intercalado: procura a próxima unidade NAL plausível.
// Likely an interleaved audio chunk: scan ahead for the next plausible video NAL sequence.
let found = scan_nal(
src,
codec,
@@ -642,7 +642,7 @@ fn rebuild_with(
);
match found {
Some(q) if nal_count > 0 => {
// O que veio antes fecha o quadro atual.
// Flush the current frame before starting the next one.
if let Some(mut s) = cur.take() {
s.size = (group_start.unwrap_or(pos) - s.off) as u32;
samples.push(s);
@@ -734,9 +734,9 @@ fn rebuild_with(
let _ = ty;
if is_vcl {
if first_of_pic {
// fecha o quadro anterior
// flush previous frame
if let Some(mut s) = cur.take() {
// tamanho até o início do grupo atual (ou deste NAL)
// frame size up to the start of the current non-VCL group (or this VCL NAL)
let end = group_start.unwrap_or(pos);
s.size = (end - s.off) as u32;
samples.push(s);
@@ -816,7 +816,7 @@ fn rebuild_with(
return None;
}
let (num, den) = match timing {
Some((units, scale)) if codec == Codec::Avc => (scale, 2 * units), // quadros por segundo = scale / (2 * units)
Some((units, scale)) if codec == Codec::Avc => (scale, 2 * units), // fps = time_scale / (2 * num_units_in_tick)
Some((units, scale)) => (scale, units),
None => (30, 1),
};
@@ -827,10 +827,10 @@ fn rebuild_with(
(num, den)
};
let fps = num as f64 / den as f64;
// Escala: tique do quadro = den, escala de tempo = num.
// Timescale: frame tick = den, timescale = num.
let (timescale, dur) = (num, den);
// Ordem de apresentação (POC) por trecho entre IDR.
// Compute presentation order (ctts composition offsets) from POC within each IDR GOP.
let mut ctts: Option<Vec<i64>> = None;
if samples.iter().all(|s| s.poc.is_some()) {
let mut offs = vec![0i64; samples.len()];
@@ -936,7 +936,7 @@ fn build_moov(
let movie_ts = 1000u32;
let movie_dur = media_dur * movie_ts as u64 / timescale as u64;
// Entrada de amostra
// Visual sample entry (`avc1` / `hvc1`)
let mut entry = vec![];
entry.extend_from_slice(&[0; 6]);
entry.extend_from_slice(&1u16.to_be_bytes());
@@ -975,18 +975,18 @@ fn build_moov(
Codec::Hevc => {
let h = hevc.unwrap();
let mut c = vec![1];
c.extend_from_slice(&h.ptl[..12.min(h.ptl.len())]); // espaço/tier/perfil, compat, restrições, nível
c.extend_from_slice(&h.ptl[..12.min(h.ptl.len())]); // profile_space/tier/profile_idc, profile_compatibility, constraint_indicator, level_idc
c.truncate(13);
while c.len() < 13 {
c.push(0);
}
c.extend_from_slice(&0xF000u16.to_be_bytes()); // segmentação espacial
c.push(0xFC); // paralelismo
c.extend_from_slice(&0xF000u16.to_be_bytes()); // min_spatial_segmentation_idc
c.push(0xFC); // parallelismType
c.push(0xFC | h.chroma as u8);
c.push(0xF8 | (h.bit_depth_luma - 8) as u8);
c.push(0xF8 | (h.bit_depth_chroma - 8) as u8);
c.extend_from_slice(&0u16.to_be_bytes()); // avgFrameRate
c.push(0x0B); // constFrameRate=0, 1 camada temporal, lengthSizeMinusOne=3
c.push(0x0B); // constantFrameRate=0, numTemporalLayers=1, lengthSizeMinusOne=3
let arrays: [(u8, &[Vec<u8>]); 3] = [(32, vps), (33, sps), (34, pps)];
let present: Vec<_> = arrays.iter().filter(|(_, v)| !v.is_empty()).collect();
c.push(present.len() as u8);
@@ -1047,7 +1047,7 @@ fn build_moov(
.collect();
let mut stbl_parts = vec![stsd, stts];
if let Some(c) = ctts {
// entradas agrupadas
// run-length encoded entries
let mut runs: Vec<(u32, u32)> = vec![];
for &v in c {
match runs.last_mut() {
@@ -1080,7 +1080,7 @@ fn build_moov(
let vmhd = full(b"vmhd", 0, 1, &[0; 8]);
let minf = bx(b"minf", &[vmhd, dinf, stbl].concat());
let mut mdhd_body = vec![];
mdhd_body.extend_from_slice(&[0; 8]); // criação/modificação
mdhd_body.extend_from_slice(&[0; 8]); // creation_time / modification_time
mdhd_body.extend_from_slice(&u32b(timescale));
mdhd_body.extend_from_slice(&u32b(media_dur as u32));
mdhd_body.extend_from_slice(&0x55C4u16.to_be_bytes()); // "und"
@@ -1100,8 +1100,8 @@ fn build_moov(
tkhd_body.extend_from_slice(&[0; 4]);
tkhd_body.extend_from_slice(&u32b(movie_dur as u32));
tkhd_body.extend_from_slice(&[0; 8]);
tkhd_body.extend_from_slice(&[0; 4]); // camada, grupo
tkhd_body.extend_from_slice(&[0; 4]); // volume, reservado
tkhd_body.extend_from_slice(&[0; 4]); // layer, alternate_group
tkhd_body.extend_from_slice(&[0; 4]); // volume, reserved
for m in matrix {
tkhd_body.extend_from_slice(&u32b(m));
}
@@ -1136,7 +1136,7 @@ fn build_moov(
bx(b"moov", &[mvhd, trak].concat())
}
/// A unidade NAL parece de verdade? Valida o cabeçalho de fatia e o tamanho de SPS/PPS/AUD.
/// Checks whether a candidate NAL unit looks structurally valid (slice header, SPS/PPS/AUD sizes).
fn nal_plausible(
codec: Codec,
head: &[u8],
@@ -1167,7 +1167,7 @@ fn nal_plausible(
return false;
}
if let Some(sp) = sps {
// frame_num de IDR é sempre 0
// IDR slice `frame_num` is always 0
if t == 5 {
if let Some(fnum) = b.u(sp.log2_max_frame_num) {
return fnum == 0;
@@ -1194,7 +1194,7 @@ fn nal_plausible(
}
}
/// Quantas unidades NAL válidas seguidas (sem vãos) começam em `at` (até `max`).
/// Counts how many consecutive valid length-prefixed NAL units start at `at` (up to `max`).
fn chain_len(
buf: &[u8],
base: u64,
@@ -1232,8 +1232,8 @@ fn chain_len(
n
}
/// Próxima posição em [from, limit) onde começa uma sequência de unidades NAL plausíveis.
/// Prefere o primeiro ponto com duas ou mais unidades seguidas; senão, uma unidade isolada.
/// Finds the next offset in `[from, limit)` where a plausible NAL unit sequence begins.
/// Prefers an offset with two or more back-to-back valid NALs; falls back to a single valid NAL.
fn scan_nal(
src: &dyn Source,
codec: Codec,
@@ -1247,7 +1247,7 @@ fn scan_nal(
if limit <= from + 8 {
return None;
}
// Lê um pouco além do limite para poder seguir a cadeia de unidades.
// Read slightly past `limit` so we can verify the following NAL in the chain.
let want =
((limit - from) as usize + (cap as usize).min(4 << 20)).min((data_end - from) as usize);
let buf = read_vec(src, from, want).ok()?;
@@ -1259,7 +1259,7 @@ fn scan_nal(
if l2 >= 2 && l2 <= cap && q + 4 + l2 <= data_end {
let nb = buf[i + 4];
let good_head = match codec {
// Um quadro novo começa por parâmetros/AUD/SEI ou por fatia do macrobloco 0.
// A new access unit starts with parameter sets/AUD/SEI or a slice at macroblock 0.
Codec::Avc => {
avc_nal_ok(nb)
&& (matches!(nb & 0x1F, 6..=9)