Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions .github/workflows/windows-remux-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,12 @@ jobs:
run: |
python -m pip install --upgrade pip
python -m pip install pytest
choco install ffmpeg -y --no-progress
ffmpeg -version
ffprobe -version
winget install --id Gyan.FFmpeg -e --silent --accept-source-agreements --accept-package-agreements --disable-interactivity
$ffPath = (Get-ChildItem "$env:LOCALAPPDATA\Microsoft\WinGet\Packages\Gyan.FFmpeg*" -Directory | Select-Object -First 1).FullName
$binDir = (Get-ChildItem -Path $ffPath -Recurse -Filter "ffmpeg.exe" | Select-Object -First 1).DirectoryName
echo "$binDir" | Out-File -FilePath $env:GITHUB_PATH -Append -Encoding utf8
& "$binDir\ffmpeg.exe" -version
& "$binDir\ffprobe.exe" -version

- name: Run Targeted Remux Tests
shell: pwsh
Expand Down
5 changes: 2 additions & 3 deletions core/file_types.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Types de fichiers supportés en entrée.

Liste adaptée de mkvtoolnix (common/file_types.cpp) pour couvrir tous les
formats sources manipulables par mkvmerge/ffmpeg : conteneurs vidéo,
Couvre les formats sources manipulables par FFmpeg : conteneurs vidéo,
streams élémentaires, pistes audio, sous-titres, playlists Blu-ray.
"""

Expand Down Expand Up @@ -89,7 +88,7 @@ def _all_extensions() -> list[str]:


def build_qt_filter(video_only: bool = False) -> str:
"""Construit la chaîne de filtre QFileDialog à la manière de mkvtoolnix GUI.
"""Construit la chaîne de filtre QFileDialog.

Format : "All supported media files (*.mkv *.mp4 ...);;All files (*);;Type1 (*.ext1 ...);;..."
"""
Expand Down
9 changes: 4 additions & 5 deletions core/workflows/encode/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from core.workflows.remux import RemuxWorkflow, write_mediainfo_nfo
from core.workflows.remux_timeline_sync import (
LiveSyncSession,
MkvmergeLikeTimelineSync,
FfmpegTimelineSync,
TimelineSyncFallbackHelper,
)
from core.workflows.encode.models import (
Expand Down Expand Up @@ -827,7 +827,7 @@ def _prepare_multisource_sync(
allow_live: bool = True,
) -> tuple[dict[tuple[Path, int, str], tuple[int, int]], list[Path | str], LiveSyncSession | None, bool]:
"""
Prépare la normalisation timeline mkvmerge-like pour les flux multi-source
Prépare la normalisation timeline pour les flux multi-source
dans le workflow encode.
"""
source_idx_local = {p: i for i, p in enumerate(all_sources)}
Expand Down Expand Up @@ -899,7 +899,7 @@ def _prepare_multisource_sync(
)

sync_sources = [SourceInput(path=p, file_index=i, tracks=[]) for i, p in enumerate(all_sources)]
syncer = MkvmergeLikeTimelineSync(
syncer = FfmpegTimelineSync(
ffmpeg_bin=self._ffmpeg,
ffmpeg_thread_args=self._ffmpeg_thread_args(),
log_cb=lambda msg: self.log_message.emit("INFO", msg),
Expand Down Expand Up @@ -3175,8 +3175,7 @@ def _run_with_metadata_inject(self, config: EncodeConfig) -> TaskSignals:
-map 1:s? -c:s copy (subs depuis source)
-map_metadata/-map_chapters/... (tags/chapitres/track-meta)
output.mkv
Pas de dépendance MKVToolNix, pas de fichier audio intermédiaire.
La source n'est jamais modifiée.
Pas de fichier audio intermédiaire. La source n'est jamais modifiée.
"""
signals = TaskSignals()
executor = ThreadPoolExecutor(max_workers=1)
Expand Down
15 changes: 7 additions & 8 deletions core/workflows/matroska_header_editor.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
"""
core/workflows/matroska_header_editor.py

Matroska Segment Info editor (MuxingApp) with in-place binary patching strategy
inspired by mkvpropedit/kax_analyzer.
Matroska Segment Info editor (MuxingApp) with in-place binary patching strategy.

Key goals:
- no temp output file / no full-file copy fallback
Expand Down Expand Up @@ -38,7 +37,7 @@ class MatroskaSegmentInfoHeaderEditorOptions:
info_id: bytes = _INFO_ID
muxing_app_id: bytes = b"\x4d\x80"
writing_app_id: bytes = b"\x57\x41"
# Kept for API compatibility. Parsing is now file-wide (mkvpropedit-like).
# Kept for API compatibility. Parsing is now file-wide.
header_scan_bytes: int = 8 * 1024 * 1024
edit_muxing_app: bool = True
edit_writing_app: bool = False
Expand Down Expand Up @@ -203,7 +202,7 @@ def _build_replaced_info_element(
return info.element_id + new_info_size + new_info_payload

# ------------------------------------------------------------------
# Core update flow (mkvpropedit-like for Info)
# Core update flow for Info
# ------------------------------------------------------------------

def _apply_muxing_app_replace_with_header_rebuild_impl(
Expand Down Expand Up @@ -250,7 +249,7 @@ def _apply_muxing_app_replace_with_header_rebuild_impl(

before_size = state.file_size

# mkvpropedit-like sequence for one level-1 element (Info).
# Sequence for one level-1 element (Info).
self._fix_unknown_size_for_last_level1_element(fh, state)
self._overwrite_all_instances(fh, state, self.options.info_id)
self._merge_void_elements(fh, state)
Expand Down Expand Up @@ -283,7 +282,7 @@ def _apply_muxing_app_replace_with_header_rebuild_impl(
)

# ------------------------------------------------------------------
# Analyzer (kax_analyzer-like, fast + meta seek recursion)
# Analyzer (fast + meta seek recursion)
# ------------------------------------------------------------------

def _analyze_file(self, fh: BinaryIO, *, parse_fast: bool) -> _AnalyzerState:
Expand Down Expand Up @@ -621,7 +620,7 @@ def _create_new_meta_seek_at_start(self, fh: BinaryIO, state: _AnalyzerState, se
break
if e.element_id != _VOID_ID:
continue
# Same guard as mkvpropedit: avoid "+1 byte" residual hole.
# Guard: avoid "+1 byte" residual hole.
slot_span = self._element_span(e)
if slot_span != needed and slot_span < needed + 2:
continue
Expand Down Expand Up @@ -749,7 +748,7 @@ def _handle_void_elements(self, fh: BinaryIO, state: _AnalyzerState, data_idx: i
return False

if void_size == 1:
# mkvpropedit-like handling for 1-byte gap.
# Handling for 1-byte gap.
if nxt.id_len <= 0 or nxt.size_len <= 0:
nxt = self._read_ebml_element_from_file(fh, nxt.offset, self._file_size(fh))
state.data[data_idx + 1] = nxt
Expand Down
8 changes: 3 additions & 5 deletions core/workflows/merge_dovi.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
"""
core/workflows/merge_dovi.py — Workflow d'injection DoVi RPU + HDR10+.

Extrait la logique métier de merge_dovi_hdr10plus.py et l'adapte pour
être piloté depuis l'interface Qt via ToolRunner.
Logique métier pilotée depuis l'interface Qt via ToolRunner.

Classes publiques :
FrameCountResult — résultat de la comparaison des frame counts
Expand Down Expand Up @@ -243,9 +242,8 @@ class MergeDoviWorkflow(QObject):
"""
Orchestrateur du workflow d'injection DoVi RPU + HDR10+.

Encapsule la logique de merge_dovi_hdr10plus.py en un QObject émettant
des signaux Qt pour chaque étape. Toutes les opérations lourdes s'exécutent
dans des threads secondaires via ThreadPoolExecutor.
QObject émettant des signaux Qt pour chaque étape. Toutes les opérations
lourdes s'exécutent dans des threads secondaires via ThreadPoolExecutor.

Usage :
wf = MergeDoviWorkflow(config)
Expand Down
8 changes: 4 additions & 4 deletions core/workflows/remux.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
)
from core.workflows.remux_timeline_sync import (
LiveSyncSession,
MkvmergeLikeTimelineSync,
FfmpegTimelineSync,
SyncPreparedInput,
TimelineSyncFallbackHelper,
)
Expand Down Expand Up @@ -660,7 +660,7 @@ def _task() -> None:
"INFO",
"D\u00e9calage sur piste \u00e9trang\u00e8re d\u00e9tect\u00e9 : sync live d\u00e9sactiv\u00e9, fallback fichier forc\u00e9.",
)
mapped_tracks, sync_prepared, live_sync_session = self._prepare_mkvmerge_like_sync_inputs(
mapped_tracks, sync_prepared, live_sync_session = self._prepare_timeline_sync_inputs(
run_config,
mapped_tracks,
tmp_dir,
Expand Down Expand Up @@ -827,7 +827,7 @@ def _decide_strict_interleave_with_prescan(self, config: RemuxConfig) -> bool:
)
return True

def _prepare_mkvmerge_like_sync_inputs(
def _prepare_timeline_sync_inputs(
self,
config: RemuxConfig,
mapped_tracks: list[_MappedTrack],
Expand All @@ -840,7 +840,7 @@ def _prepare_mkvmerge_like_sync_inputs(
D\u00e9l\u00e8gue la normalisation des flux \u00e9trangers \u00e0 un utilitaire d\u00e9di\u00e9 afin de
conserver une logique testable et r\u00e9utilisable hors workflow.
"""
syncer = MkvmergeLikeTimelineSync(
syncer = FfmpegTimelineSync(
ffmpeg_bin=self._ffmpeg,
ffmpeg_thread_args=self._ffmpeg_thread_args(),
log_cb=lambda msg: self.log_message.emit("INFO", msg),
Expand Down
14 changes: 7 additions & 7 deletions core/workflows/remux_timeline_sync.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""
core/workflows/remux_timeline_sync.py — utilitaire de synchronisation timeline
"mkvmerge-like" pour le remux FFmpeg multi-source.
pour le remux FFmpeg multi-source.

But:
- isoler les flux audio/sous-titres "étrangers" (hors source vidéo primaire),
Expand Down Expand Up @@ -121,7 +121,7 @@ class TimelineSyncFallbackHelper:
def __init__(
self,
*,
syncer: "MkvmergeLikeTimelineSync",
syncer: "FfmpegTimelineSync",
work_dir: Path,
ram_dir: Path | None = None,
log_cb: Callable[[str], None] | None = None,
Expand Down Expand Up @@ -166,7 +166,7 @@ def prepare(
# Identifier les pistes étrangères (hors source vidéo primaire)
source_by_index = {src.file_index: src for src in sources}
foreign_keys: set[tuple[int, int, str]] = set(
MkvmergeLikeTimelineSync._collect_foreign_targets(
FfmpegTimelineSync._collect_foreign_targets(
mapped_tracks=mapped_tracks,
source_by_index=source_by_index,
cancel_cb=cancel_cb,
Expand Down Expand Up @@ -322,7 +322,7 @@ def _prepare_fallback(
return []


class MkvmergeLikeTimelineSync:
class FfmpegTimelineSync:
"""
Prépare des entrées normalisées pour les flux multi-source à risque.
"""
Expand Down Expand Up @@ -376,7 +376,7 @@ def prepare_from_mapped_tracks(

if prepared:
self._log(
"Timeline sync (mode mkvmerge-like): "
"Timeline sync (multi-source):"
f"{len(prepared)} flux normalisé(s) avant remux final."
)

Expand Down Expand Up @@ -561,7 +561,7 @@ def _start_posix_fifo_session(
raise

self._log(
"Timeline sync live (mkvmerge-like): "
"Timeline sync live (multi-source):"
f"{len(inputs)} FIFO(s) actives pour le remux final."
)
return LiveSyncSession(
Expand Down Expand Up @@ -750,7 +750,7 @@ def _pump_stdout_to_named_pipe(
raise

self._log(
"Timeline sync live (mkvmerge-like): "
"Timeline sync live (multi-source):"
f"{len(inputs)} named pipe(s) actives pour le remux final."
)
return LiveSyncSession(
Expand Down
2 changes: 1 addition & 1 deletion launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ def _run_first_time_setup(install_dir: Path) -> int:
else:
print(
" Distribution non reconnue — installez manuellement :\n"
" ffmpeg mkvtoolnix mediainfo",
" ffmpeg mediainfo",
file=sys.stderr,
)
_setup.install_github_tools(prefix, dry_run, force=force)
Expand Down
16 changes: 0 additions & 16 deletions locales.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,6 @@
"fra": "Binaire FFprobe utilisé pour l'analyse des médias.",
"eng": "FFprobe binary used for media analysis."
},
"Binaire MKVToolNix utilisé pour le remuxage.": {
"fra": "Binaire MKVToolNix utilisé pour le remuxage.",
"eng": "MKVToolNix binary used for remuxing."
},
"Binaire MKVToolNix utilisé pour extraire des pistes.": {
"fra": "Binaire MKVToolNix utilisé pour extraire des pistes.",
"eng": "MKVToolNix binary used to extract tracks."
},
"Binaire MKVToolNix utilisé pour l'inspection des conteneurs.": {
"fra": "Binaire MKVToolNix utilisé pour l'inspection des conteneurs.",
"eng": "MKVToolNix binary used to inspect containers."
},
"Binaire MKVToolNix utilisé pour réécrire des métadonnées.": {
"fra": "Binaire MKVToolNix utilisé pour réécrire des métadonnées.",
"eng": "MKVToolNix binary used to rewrite metadata."
},
"Binaire MediaInfo utilisé pour enrichir l'inspection.": {
"fra": "Binaire MediaInfo utilisé pour enrichir l'inspection.",
"eng": "MediaInfo binary used to enrich inspection data."
Expand Down
Loading
Loading