From 71c759a057c39d4d2cc00ec99c9fa6c83f108a2d Mon Sep 17 00:00:00 2001 From: Simpel <git@simpel.cc> Date: Sun, 20 Aug 2023 22:06:25 +0200 Subject: [PATCH] rewrite: use bmxtranswrap As wrapping with ffmpeg alone didn't create valid v1.3 op1a mxf in ard zdf profile this has to be done with bmxtranswrap. This can swap audio track or silence them. But it can't insert external audio. So if external audio is provided do the swapping, muting and inserting with ffmpeg and rewrap mxf with bmxtranswrap. Else do the swapping and mu- ting with bmxtranswrap alone. Signed-off-by: Conrad Zelck <git@simpel.cc> --- MXF-Track-Swap.au3 | 422 +++++++++++++++++++++---------- README.md | 6 +- images/MXF-Track-Swap_muxing.png | Bin 8427 -> 8115 bytes 3 files changed, 288 insertions(+), 140 deletions(-) diff --git a/MXF-Track-Swap.au3 b/MXF-Track-Swap.au3 index f2e4fe1..fffdaac 100644 --- a/MXF-Track-Swap.au3 +++ b/MXF-Track-Swap.au3 @@ -3,7 +3,7 @@ #AutoIt3Wrapper_UseX64=n #AutoIt3Wrapper_Res_Comment=Swaps audio tracks in mxf files. #AutoIt3Wrapper_Res_Description=Swaps audio tracks in mxf files. -#AutoIt3Wrapper_Res_Fileversion=1.0.0.7 +#AutoIt3Wrapper_Res_Fileversion=1.0.0.8 #AutoIt3Wrapper_Res_Fileversion_AutoIncrement=p #AutoIt3Wrapper_Res_LegalCopyright=Conrad Zelck #AutoIt3Wrapper_Res_SaveSource=y @@ -307,237 +307,310 @@ WEnd #Region - track setting ; set audio tracks -Global $g_aRouting[9] +Global $g_aRoutingFFmpeg[9] +Global $g_aRoutingBMX[9] Global $g_bMuteRouted = False Global $g_bExternalWavRouted = False ; track 1 Select Case GUICtrlRead($g_hRm1) = $GUI_CHECKED - $g_aRouting[1] = "1:0" + $g_aRoutingFFmpeg[1] = "1:0" + $g_aRoutingBMX[1] = "s1" $g_bMuteRouted = True Case GUICtrlRead($g_hR11) = $GUI_CHECKED - $g_aRouting[1] = "0:1" + $g_aRoutingFFmpeg[1] = "0:1" + $g_aRoutingBMX[1] = "0" Case GUICtrlRead($g_hR21) = $GUI_CHECKED - $g_aRouting[1] = "0:2" + $g_aRoutingFFmpeg[1] = "0:2" + $g_aRoutingBMX[1] = "1" Case GUICtrlRead($g_hR31) = $GUI_CHECKED - $g_aRouting[1] = "0:3" + $g_aRoutingFFmpeg[1] = "0:3" + $g_aRoutingBMX[1] = "2" Case GUICtrlRead($g_hR41) = $GUI_CHECKED - $g_aRouting[1] = "0:4" + $g_aRoutingFFmpeg[1] = "0:4" + $g_aRoutingBMX[1] = "3" Case GUICtrlRead($g_hR51) = $GUI_CHECKED - $g_aRouting[1] = "0:5" + $g_aRoutingFFmpeg[1] = "0:5" + $g_aRoutingBMX[1] = "4" Case GUICtrlRead($g_hR61) = $GUI_CHECKED - $g_aRouting[1] = "0:6" + $g_aRoutingFFmpeg[1] = "0:6" + $g_aRoutingBMX[1] = "5" Case GUICtrlRead($g_hR71) = $GUI_CHECKED - $g_aRouting[1] = "0:7" + $g_aRoutingFFmpeg[1] = "0:7" + $g_aRoutingBMX[1] = "6" Case GUICtrlRead($g_hR81) = $GUI_CHECKED - $g_aRouting[1] = "0:8" + $g_aRoutingFFmpeg[1] = "0:8" + $g_aRoutingBMX[1] = "7" Case GUICtrlRead($g_hRL1) = $GUI_CHECKED - $g_aRouting[1] = '"[L]"' + $g_aRoutingFFmpeg[1] = '"[L]"' $g_bExternalWavRouted = True Case GUICtrlRead($g_hRR1) = $GUI_CHECKED - $g_aRouting[1] = '"[R]"' + $g_aRoutingFFmpeg[1] = '"[R]"' $g_bExternalWavRouted = True EndSelect ; track 2 Select Case GUICtrlRead($g_hRm2) = $GUI_CHECKED - $g_aRouting[2] = "1:0" + $g_aRoutingFFmpeg[2] = "1:0" + $g_aRoutingBMX[2] = "s1" $g_bMuteRouted = True Case GUICtrlRead($g_hR12) = $GUI_CHECKED - $g_aRouting[2] = "0:1" + $g_aRoutingFFmpeg[2] = "0:1" + $g_aRoutingBMX[2] = "0" Case GUICtrlRead($g_hR22) = $GUI_CHECKED - $g_aRouting[2] = "0:2" + $g_aRoutingFFmpeg[2] = "0:2" + $g_aRoutingBMX[2] = "1" Case GUICtrlRead($g_hR32) = $GUI_CHECKED - $g_aRouting[2] = "0:3" + $g_aRoutingFFmpeg[2] = "0:3" + $g_aRoutingBMX[2] = "2" Case GUICtrlRead($g_hR42) = $GUI_CHECKED - $g_aRouting[2] = "0:4" + $g_aRoutingFFmpeg[2] = "0:4" + $g_aRoutingBMX[2] = "3" Case GUICtrlRead($g_hR52) = $GUI_CHECKED - $g_aRouting[2] = "0:5" + $g_aRoutingFFmpeg[2] = "0:5" + $g_aRoutingBMX[2] = "4" Case GUICtrlRead($g_hR62) = $GUI_CHECKED - $g_aRouting[2] = "0:6" + $g_aRoutingFFmpeg[2] = "0:6" + $g_aRoutingBMX[2] = "5" Case GUICtrlRead($g_hR72) = $GUI_CHECKED - $g_aRouting[2] = "0:7" + $g_aRoutingFFmpeg[2] = "0:7" + $g_aRoutingBMX[2] = "6" Case GUICtrlRead($g_hR82) = $GUI_CHECKED - $g_aRouting[2] = "0:8" + $g_aRoutingFFmpeg[2] = "0:8" + $g_aRoutingBMX[2] = "7" Case GUICtrlRead($g_hRL2) = $GUI_CHECKED - $g_aRouting[2] = '"[L]"' + $g_aRoutingFFmpeg[2] = '"[L]"' $g_bExternalWavRouted = True Case GUICtrlRead($g_hRR2) = $GUI_CHECKED - $g_aRouting[2] = '"[R]"' + $g_aRoutingFFmpeg[2] = '"[R]"' $g_bExternalWavRouted = True EndSelect ; track 3 Select Case GUICtrlRead($g_hRm3) = $GUI_CHECKED - $g_aRouting[3] = "1:0" + $g_aRoutingFFmpeg[3] = "1:0" + $g_aRoutingBMX[3] = "s1" $g_bMuteRouted = True Case GUICtrlRead($g_hR13) = $GUI_CHECKED - $g_aRouting[3] = "0:1" + $g_aRoutingFFmpeg[3] = "0:1" + $g_aRoutingBMX[3] = "0" Case GUICtrlRead($g_hR23) = $GUI_CHECKED - $g_aRouting[3] = "0:2" + $g_aRoutingFFmpeg[3] = "0:2" + $g_aRoutingBMX[3] = "1" Case GUICtrlRead($g_hR33) = $GUI_CHECKED - $g_aRouting[3] = "0:3" + $g_aRoutingFFmpeg[3] = "0:3" + $g_aRoutingBMX[3] = "2" Case GUICtrlRead($g_hR43) = $GUI_CHECKED - $g_aRouting[3] = "0:4" + $g_aRoutingFFmpeg[3] = "0:4" + $g_aRoutingBMX[3] = "3" Case GUICtrlRead($g_hR53) = $GUI_CHECKED - $g_aRouting[3] = "0:5" + $g_aRoutingFFmpeg[3] = "0:5" + $g_aRoutingBMX[3] = "4" Case GUICtrlRead($g_hR63) = $GUI_CHECKED - $g_aRouting[3] = "0:6" + $g_aRoutingFFmpeg[3] = "0:6" + $g_aRoutingBMX[3] = "5" Case GUICtrlRead($g_hR73) = $GUI_CHECKED - $g_aRouting[3] = "0:7" + $g_aRoutingFFmpeg[3] = "0:7" + $g_aRoutingBMX[3] = "6" Case GUICtrlRead($g_hR83) = $GUI_CHECKED - $g_aRouting[3] = "0:8" + $g_aRoutingFFmpeg[3] = "0:8" + $g_aRoutingBMX[3] = "7" Case GUICtrlRead($g_hRL3) = $GUI_CHECKED - $g_aRouting[3] = '"[L]"' + $g_aRoutingFFmpeg[3] = '"[L]"' $g_bExternalWavRouted = True Case GUICtrlRead($g_hRR3) = $GUI_CHECKED - $g_aRouting[3] = '"[R]"' + $g_aRoutingFFmpeg[3] = '"[R]"' $g_bExternalWavRouted = True EndSelect ; track 4 Select Case GUICtrlRead($g_hRm4) = $GUI_CHECKED - $g_aRouting[4] = "1:0" + $g_aRoutingFFmpeg[4] = "1:0" + $g_aRoutingBMX[4] = "s1" $g_bMuteRouted = True Case GUICtrlRead($g_hR14) = $GUI_CHECKED - $g_aRouting[4] = "0:1" + $g_aRoutingFFmpeg[4] = "0:1" + $g_aRoutingBMX[4] = "0" Case GUICtrlRead($g_hR24) = $GUI_CHECKED - $g_aRouting[4] = "0:2" + $g_aRoutingFFmpeg[4] = "0:2" + $g_aRoutingBMX[4] = "1" Case GUICtrlRead($g_hR34) = $GUI_CHECKED - $g_aRouting[4] = "0:3" + $g_aRoutingFFmpeg[4] = "0:3" + $g_aRoutingBMX[4] = "2" Case GUICtrlRead($g_hR44) = $GUI_CHECKED - $g_aRouting[4] = "0:4" + $g_aRoutingFFmpeg[4] = "0:4" + $g_aRoutingBMX[4] = "3" Case GUICtrlRead($g_hR54) = $GUI_CHECKED - $g_aRouting[4] = "0:5" + $g_aRoutingFFmpeg[4] = "0:5" + $g_aRoutingBMX[4] = "4" Case GUICtrlRead($g_hR64) = $GUI_CHECKED - $g_aRouting[4] = "0:6" + $g_aRoutingFFmpeg[4] = "0:6" + $g_aRoutingBMX[4] = "5" Case GUICtrlRead($g_hR74) = $GUI_CHECKED - $g_aRouting[4] = "0:7" + $g_aRoutingFFmpeg[4] = "0:7" + $g_aRoutingBMX[4] = "6" Case GUICtrlRead($g_hR84) = $GUI_CHECKED - $g_aRouting[4] = "0:8" + $g_aRoutingFFmpeg[4] = "0:8" + $g_aRoutingBMX[4] = "7" Case GUICtrlRead($g_hRL4) = $GUI_CHECKED - $g_aRouting[4] = '"[L]"' + $g_aRoutingFFmpeg[4] = '"[L]"' $g_bExternalWavRouted = True Case GUICtrlRead($g_hRR4) = $GUI_CHECKED - $g_aRouting[4] = '"[R]"' + $g_aRoutingFFmpeg[4] = '"[R]"' $g_bExternalWavRouted = True EndSelect ; track 5 Select Case GUICtrlRead($g_hRm5) = $GUI_CHECKED - $g_aRouting[5] = "1:0" + $g_aRoutingFFmpeg[5] = "1:0" + $g_aRoutingBMX[5] = "s1" $g_bMuteRouted = True Case GUICtrlRead($g_hR15) = $GUI_CHECKED - $g_aRouting[5] = "0:1" + $g_aRoutingFFmpeg[5] = "0:1" + $g_aRoutingBMX[5] = "0" Case GUICtrlRead($g_hR25) = $GUI_CHECKED - $g_aRouting[5] = "0:2" + $g_aRoutingFFmpeg[5] = "0:2" + $g_aRoutingBMX[5] = "1" Case GUICtrlRead($g_hR35) = $GUI_CHECKED - $g_aRouting[5] = "0:3" + $g_aRoutingFFmpeg[5] = "0:3" + $g_aRoutingBMX[5] = "2" Case GUICtrlRead($g_hR45) = $GUI_CHECKED - $g_aRouting[5] = "0:4" + $g_aRoutingFFmpeg[5] = "0:4" + $g_aRoutingBMX[5] = "3" Case GUICtrlRead($g_hR55) = $GUI_CHECKED - $g_aRouting[5] = "0:5" + $g_aRoutingFFmpeg[5] = "0:5" + $g_aRoutingBMX[5] = "4" Case GUICtrlRead($g_hR65) = $GUI_CHECKED - $g_aRouting[5] = "0:6" + $g_aRoutingFFmpeg[5] = "0:6" + $g_aRoutingBMX[5] = "5" Case GUICtrlRead($g_hR75) = $GUI_CHECKED - $g_aRouting[5] = "0:7" + $g_aRoutingFFmpeg[5] = "0:7" + $g_aRoutingBMX[5] = "6" Case GUICtrlRead($g_hR85) = $GUI_CHECKED - $g_aRouting[5] = "0:8" + $g_aRoutingFFmpeg[5] = "0:8" + $g_aRoutingBMX[5] = "7" Case GUICtrlRead($g_hRL5) = $GUI_CHECKED - $g_aRouting[5] = '"[L]"' + $g_aRoutingFFmpeg[5] = '"[L]"' $g_bExternalWavRouted = True Case GUICtrlRead($g_hRR5) = $GUI_CHECKED - $g_aRouting[5] = '"[R]"' + $g_aRoutingFFmpeg[5] = '"[R]"' $g_bExternalWavRouted = True EndSelect ; track 6 Select Case GUICtrlRead($g_hRm6) = $GUI_CHECKED - $g_aRouting[6] = "1:0" + $g_aRoutingFFmpeg[6] = "1:0" + $g_aRoutingBMX[6] = "s1" $g_bMuteRouted = True Case GUICtrlRead($g_hR16) = $GUI_CHECKED - $g_aRouting[6] = "0:1" + $g_aRoutingFFmpeg[6] = "0:1" + $g_aRoutingBMX[6] = "0" Case GUICtrlRead($g_hR26) = $GUI_CHECKED - $g_aRouting[6] = "0:2" + $g_aRoutingFFmpeg[6] = "0:2" + $g_aRoutingBMX[6] = "1" Case GUICtrlRead($g_hR36) = $GUI_CHECKED - $g_aRouting[6] = "0:3" + $g_aRoutingFFmpeg[6] = "0:3" + $g_aRoutingBMX[6] = "2" Case GUICtrlRead($g_hR46) = $GUI_CHECKED - $g_aRouting[6] = "0:4" + $g_aRoutingFFmpeg[6] = "0:4" + $g_aRoutingBMX[6] = "3" Case GUICtrlRead($g_hR56) = $GUI_CHECKED - $g_aRouting[6] = "0:5" + $g_aRoutingFFmpeg[6] = "0:5" + $g_aRoutingBMX[6] = "4" Case GUICtrlRead($g_hR66) = $GUI_CHECKED - $g_aRouting[6] = "0:6" + $g_aRoutingFFmpeg[6] = "0:6" + $g_aRoutingBMX[6] = "5" Case GUICtrlRead($g_hR76) = $GUI_CHECKED - $g_aRouting[6] = "0:7" + $g_aRoutingFFmpeg[6] = "0:7" + $g_aRoutingBMX[6] = "6" Case GUICtrlRead($g_hR86) = $GUI_CHECKED - $g_aRouting[6] = "0:8" + $g_aRoutingFFmpeg[6] = "0:8" + $g_aRoutingBMX[6] = "7" Case GUICtrlRead($g_hRL6) = $GUI_CHECKED - $g_aRouting[6] = '"[L]"' + $g_aRoutingFFmpeg[6] = '"[L]"' $g_bExternalWavRouted = True Case GUICtrlRead($g_hRR6) = $GUI_CHECKED - $g_aRouting[6] = '"[R]"' + $g_aRoutingFFmpeg[6] = '"[R]"' $g_bExternalWavRouted = True EndSelect ; track 7 Select Case GUICtrlRead($g_hRm7) = $GUI_CHECKED - $g_aRouting[7] = "1:0" + $g_aRoutingFFmpeg[7] = "1:0" + $g_aRoutingBMX[7] = "s1" $g_bMuteRouted = True Case GUICtrlRead($g_hR17) = $GUI_CHECKED - $g_aRouting[7] = "0:1" + $g_aRoutingFFmpeg[7] = "0:1" + $g_aRoutingBMX[7] = "0" Case GUICtrlRead($g_hR27) = $GUI_CHECKED - $g_aRouting[7] = "0:2" + $g_aRoutingFFmpeg[7] = "0:2" + $g_aRoutingBMX[7] = "1" Case GUICtrlRead($g_hR37) = $GUI_CHECKED - $g_aRouting[7] = "0:3" + $g_aRoutingFFmpeg[7] = "0:3" + $g_aRoutingBMX[7] = "2" Case GUICtrlRead($g_hR47) = $GUI_CHECKED - $g_aRouting[7] = "0:4" + $g_aRoutingFFmpeg[7] = "0:4" + $g_aRoutingBMX[7] = "3" Case GUICtrlRead($g_hR57) = $GUI_CHECKED - $g_aRouting[7] = "0:5" + $g_aRoutingFFmpeg[7] = "0:5" + $g_aRoutingBMX[7] = "4" Case GUICtrlRead($g_hR67) = $GUI_CHECKED - $g_aRouting[7] = "0:6" + $g_aRoutingFFmpeg[7] = "0:6" + $g_aRoutingBMX[7] = "5" Case GUICtrlRead($g_hR77) = $GUI_CHECKED - $g_aRouting[7] = "0:7" + $g_aRoutingFFmpeg[7] = "0:7" + $g_aRoutingBMX[7] = "6" Case GUICtrlRead($g_hR87) = $GUI_CHECKED - $g_aRouting[7] = "0:8" + $g_aRoutingFFmpeg[7] = "0:8" + $g_aRoutingBMX[7] = "7" Case GUICtrlRead($g_hRL7) = $GUI_CHECKED - $g_aRouting[7] = '"[L]"' + $g_aRoutingFFmpeg[7] = '"[L]"' $g_bExternalWavRouted = True Case GUICtrlRead($g_hRR7) = $GUI_CHECKED - $g_aRouting[7] = '"[R]"' + $g_aRoutingFFmpeg[7] = '"[R]"' $g_bExternalWavRouted = True EndSelect ; track 8 Select Case GUICtrlRead($g_hRm8) = $GUI_CHECKED - $g_aRouting[8] = "1:0" + $g_aRoutingFFmpeg[8] = "1:0" + $g_aRoutingBMX[8] = "s1" $g_bMuteRouted = True Case GUICtrlRead($g_hR18) = $GUI_CHECKED - $g_aRouting[8] = "0:1" + $g_aRoutingFFmpeg[8] = "0:1" + $g_aRoutingBMX[8] = "0" Case GUICtrlRead($g_hR28) = $GUI_CHECKED - $g_aRouting[8] = "0:2" + $g_aRoutingFFmpeg[8] = "0:2" + $g_aRoutingBMX[8] = "1" Case GUICtrlRead($g_hR38) = $GUI_CHECKED - $g_aRouting[8] = "0:3" + $g_aRoutingFFmpeg[8] = "0:3" + $g_aRoutingBMX[8] = "2" Case GUICtrlRead($g_hR48) = $GUI_CHECKED - $g_aRouting[8] = "0:4" + $g_aRoutingFFmpeg[8] = "0:4" + $g_aRoutingBMX[8] = "3" Case GUICtrlRead($g_hR58) = $GUI_CHECKED - $g_aRouting[8] = "0:5" + $g_aRoutingFFmpeg[8] = "0:5" + $g_aRoutingBMX[8] = "4" Case GUICtrlRead($g_hR68) = $GUI_CHECKED - $g_aRouting[8] = "0:6" + $g_aRoutingFFmpeg[8] = "0:6" + $g_aRoutingBMX[8] = "5" Case GUICtrlRead($g_hR78) = $GUI_CHECKED - $g_aRouting[8] = "0:7" + $g_aRoutingFFmpeg[8] = "0:7" + $g_aRoutingBMX[8] = "6" Case GUICtrlRead($g_hR88) = $GUI_CHECKED - $g_aRouting[8] = "0:8" + $g_aRoutingFFmpeg[8] = "0:8" + $g_aRoutingBMX[8] = "7" Case GUICtrlRead($g_hRL8) = $GUI_CHECKED - $g_aRouting[8] = '"[L]"' + $g_aRoutingFFmpeg[8] = '"[L]"' $g_bExternalWavRouted = True Case GUICtrlRead($g_hRR8) = $GUI_CHECKED - $g_aRouting[8] = '"[R]"' + $g_aRoutingFFmpeg[8] = '"[R]"' $g_bExternalWavRouted = True EndSelect #EndRegion - track setting -;~ _ArrayDisplay($g_aRouting) -For $i = 1 To UBound($g_aRouting) -1 - ConsoleWrite($g_aRouting[$i] & @CRLF) +;~ _ArrayDisplay($g_aRoutingFFmpeg) +For $i = 1 To UBound($g_aRoutingFFmpeg) -1 + ConsoleWrite($g_aRoutingFFmpeg[$i] & @CRLF) Next ConsoleWrite("$g_bMuteRouted: " & $g_bMuteRouted & @CRLF) ConsoleWrite("$g_bExternalWavRouted: " & $g_bExternalWavRouted & @CRLF) @@ -546,9 +619,12 @@ SplashTextOn("Be patient", "MXF-Track-Swap will be prepared ...", 300, 50) If Not FileExists(@TempDir & "\ffmpeg.exe") Then FileInstall('K:\ffmpeg\bin\ffmpeg.exe', @TempDir & "\ffmpeg.exe", $FC_OVERWRITE) EndIf +If Not FileExists(@TempDir & "\bmxtranswrap.exe") Then + FileInstall('K:\bmxtranswrap\bmxtranswrap.exe', @TempDir & "\bmxtranswrap.exe", $FC_OVERWRITE) +EndIf SplashOff() -Local $sPathFFmpeg = @TempDir & "\" +Local $sPathTempFolder = @TempDir & "\" Global $g_hTimerStart Global $g_sStdErrAll @@ -595,65 +671,101 @@ EndFunc Func _ReWrap() $g_hTimerStart = TimerInit() GUIDelete($g_hGUI) - $g_hGUI = GUICreate("MXF-Track-Swap Muxing", 600, 160) + $g_hGUI = GUICreate("MXF-Track-Swap Muxing", 600, 240) GUICtrlCreateLabel("MXF-File: " & _FileName($g_sMXFFile), 10, 10, 580, 30) GUICtrlSetFont(-1, 14, 400, 0, "Courier New") - GUICtrlCreateLabel("Rewrapping:", 10, 50, 580, 30) + Global $g_hLabelInsert = GUICtrlCreateLabel("Insert Audio:", 10, 50, 580, 30) GUICtrlSetFont(-1, 12, 400, 0, "Courier New") Global $Progress1 = GUICtrlCreateProgress(10, 80, 580, 20) - Global $Edit = GUICtrlCreateLabel("", 10, 120, 260, 30) + GUICtrlCreateLabel("Rewrapping:", 10, 120, 580, 30) + GUICtrlSetFont(-1, 12, 400, 0, "Courier New") + Global $Progress2 = GUICtrlCreateProgress(10, 150, 580, 20) + Global $Edit = GUICtrlCreateLabel("", 10, 200, 260, 60) GUICtrlSetFont(-1, 14, 400, 0, "Courier New") - Global $g_hLabelRunningTime = GUICtrlCreateLabel("", 440, 120, 150, 30, $SS_RIGHT) + Global $g_hLabelRunningTime = GUICtrlCreateLabel("", 440, 200, 150, 30, $SS_CENTER) GUICtrlSetFont(-1, 14, 400, 0, "Courier New") GUISetState(@SW_SHOW) - ;~ Code zum Remuxen: Video erhalten, Audio: 1>5, 2>6, 3>3, 4>4, 5 mute, 6 mute, 7>L, 8>R - ;~ ffmpeg -i Video.mxf -f lavfi -i anullsrc=r=48000:cl=mono -i Stereo.wav -ar 48000 -filter_complex "[2:a]apad,channelsplit=channel_layout=stereo[L][R]" -map 0:0 -map 0:5 -map 0:6 -map 0:3 -map 0:4 -map 1:0 -map 1:0 -map "[L]" -map "[R]" -c:v copy -c:a pcm_s24le -shortest -y Video_swapped.mxf - Local $sCommand - ; video file - $sCommand = '-i "' & $g_sMXFFile & '"' - ; muted source - If $g_bMuteRouted Then - $sCommand &= ' -f lavfi -i anullsrc=r=48000:cl=mono' - EndIf - ; external wav file + ; do everything with bmxwrap at the end, as only this creates valid v1.3 mxf files + ; bmxwrap can't insert external audio, so if that should be done, run ffmpeg first + Local $sFFmpegCommand, $sBMXCommand, $sSuffix, $sSuffixTemp + For $i = 1 To UBound($g_aRoutingFFmpeg) -1 + $sSuffix &= '_' & $i & '-' & StringRegExpReplace(StringRegExpReplace($g_aRoutingFFmpeg[$i], "\d:", ""), '[\[\]"]', "") + Next + $sSuffixTemp = $sSuffix & '_ffmpegTemp.mxf"' + $sSuffix &= '.mxf"' + + ; this is the default bmxtranswrap command line + ; set TC 10:00:00:00 + $sBMXCommand = '-y 10:00:00:00' + ; type RDD09 + $sBMXCommand &= ' -t rdd9' + ; Active Format Descriptor 4-bit code from table 1 in SMPTE ST 2016-1 - full frame 16:9 + $sBMXCommand &= ' --afd 8' + ; the ARD ZDF HDF profile for op1a/rdd9 + $sBMXCommand &= ' --ard-zdf-hdf' + ; print progress percentage to stdout + $sBMXCommand &= ' -p' + ; set the wave essence descriptor channel assignment label which identifies the audio layout mode in operation + $sBMXCommand &= ' --audio-layout as11-mode-0' + If $g_bExternalWavRouted Then - $sCommand &= ' -i "' & $g_sWAVFile & '" -ar 48000 -filter_complex "[' + ; ffmpeg first + ;~ Code zum Remuxen: Video erhalten, Audio: 1>5, 2>6, 3>3, 4>4, 5 mute, 6 mute, 7>L, 8>R + ;~ ffmpeg -i Video.mxf -f lavfi -i anullsrc=r=48000:cl=mono -i Stereo.wav -ar 48000 -filter_complex "[2:a]apad,channelsplit=channel_layout=stereo[L][R]" -map 0:0 -map 0:5 -map 0:6 -map 0:3 -map 0:4 -map 1:0 -map 1:0 -map "[L]" -map "[R]" -c:v copy -c:a pcm_s24le -shortest -y Video_swapped.mxf + ; video file + $sFFmpegCommand = '-i "' & $g_sMXFFile & '"' + ; muted source + If $g_bMuteRouted Then + $sFFmpegCommand &= ' -f lavfi -i anullsrc=r=48000:cl=mono' + EndIf + ; external wav file + $sFFmpegCommand &= ' -i "' & $g_sWAVFile & '" -ar 48000 -filter_complex "[' If Not $g_bMuteRouted Then - $sCommand &= '1' + $sFFmpegCommand &= '1' Else - $sCommand &= '2' + $sFFmpegCommand &= '2' EndIf - $sCommand &= ':a]apad,channelsplit=channel_layout=stereo[L][R]"' + $sFFmpegCommand &= ':a]apad,channelsplit=channel_layout=stereo[L][R]"' + ; video mapping + $sFFmpegCommand &= ' -map 0:0' + ; audio mapping + For $i = 1 To UBound($g_aRoutingFFmpeg) -1 + $sFFmpegCommand &= ' -map ' & $g_aRoutingFFmpeg[$i] + Next + ; copy video, set audio to 24 bit, use shortest file (always the mxf file) as length, overwrite existing file + $sFFmpegCommand &= ' -c:v copy -c:a pcm_s24le -shortest -y' + ; set encoding date as ffmpeg otherwise wouldn't create a valid op1a v1.3 file + Local $sDate + $sDate = _NowCalc() + $sDate = StringReplace($sDate, "/", "-") & ".000" ; including ms + $sFFmpegCommand &= ' -metadata creation_time="' & $sDate & '"' + ; output file + $sFFmpegCommand &= ' "' & @TempDir & '\' & _StripFileExtension(_FileName($g_sMXFFile)) & $sSuffixTemp + ConsoleWrite("$sFFmpegcommand: " & $sFFmpegCommand & @CRLF) + _runFFmpeg('ffmpeg ' & $sFFmpegCommand, $sPathTempFolder) + ; bmxtranswrap second + _runBMXwrap('bmxtranswrap ' & $sBMXCommand & ' -o "' & @TempDir & '\' & _StripFileExtension(_FileName($g_sMXFFile)) & $sSuffix & ' "' & @TempDir & '\' & _StripFileExtension(_FileName($g_sMXFFile)) & $sSuffixTemp, $sPathTempFolder) + Else + GUICtrlSetState($Progress1, $GUI_DISABLE) ; no external audio inserted + GUICtrlSetState($g_hLabelInsert, $GUI_DISABLE) ; no external audio inserted + ; add audio mapping to bmx command + ; '--track-map "4;5;0;1;2;3;s1;s1"' + ; audio mapping + $sBMXCommand &= ' --track-map "' + For $i = 1 To UBound($g_aRoutingBMX) -1 + $sBMXCommand &= $g_aRoutingBMX[$i] & ';' + Next + $sBMXCommand = StringTrimRight($sBMXCommand, 1) ; remove the last semicolon + $sBMXCommand &= '"' + _runBMXwrap('bmxtranswrap ' & $sBMXCommand & ' -o "' & @TempDir & '\' & _StripFileExtension(_FileName($g_sMXFFile)) & $sSuffix & ' "' & $g_sMXFFile & '"', $sPathTempFolder) EndIf - ; video mapping - $sCommand &= ' -map 0:0' - ; audio mapping - For $i = 1 To UBound($g_aRouting) -1 - $sCommand &= ' -map ' & $g_aRouting[$i] - Next - ; copy video, set audio to 24 bit, use shortest file (always the mxf file) as length, overwrite existing file - $sCommand &= ' -c:v copy -c:a pcm_s24le -shortest -y' - ; set encoding date as ffmpeg otherwise wouldn't create a valid op1a v1.3 file - Local $sDate - $sDate = _NowCalc() - $sDate = StringReplace($sDate, "/", "-") & ".000" ; including ms - $sCommand &= ' -metadata creation_time="' & $sDate & '"' - ; output file - Local $sSuffix - For $i = 1 To UBound($g_aRouting) -1 - $sSuffix &= '_' & $i & '-' & StringRegExpReplace(StringRegExpReplace($g_aRouting[$i], "\d:", ""), '[\[\]"]', "") - Next - $sSuffix &= '.mxf"' - $sCommand &= ' "' & @TempDir & '\' & _StripFileExtension(_FileName($g_sMXFFile)) & $sSuffix - ConsoleWrite("$command: " & $sCommand & @CRLF) - _runFFmpeg('ffmpeg ' & $sCommand, $sPathFFmpeg, 1) GUICtrlSetData($Edit, "Ready") WinSetOnTop($g_hGUI, "", $WINDOWS_ONTOP) EndFunc -Func _runFFmpeg($command, $wd, $iProgress) +Func _runFFmpeg($command, $wd) Local $hPid = Run('"' & @ComSpec & '" /c ' & $command, $wd, @SW_HIDE, $STDOUT_CHILD + $STDERR_CHILD) Local $sStdErr, $sTimer Local $iTicksDuration = 0, $iTicksTime = 0, $iTimer @@ -666,10 +778,31 @@ Func _runFFmpeg($command, $wd, $iProgress) If Not $iTicksDuration Then $iTicksDuration = _GetDuration($sStdErr) $iTicksTime = _GetTime($sStdErr) If Not @error Then $sStdErr = "" - Switch $iProgress - Case 1 - GUICtrlSetData($Progress1, $iTicksTime * 100 / $iTicksDuration) - EndSwitch + GUICtrlSetData($Progress1, $iTicksTime * 100 / $iTicksDuration) + EndIf + $iTimer = TimerDiff($g_hTimerStart) + $sTimer = _Zeit($iTimer) + If GUICtrlRead($g_hLabelRunningTime) <> $sTimer Then + GUICtrlSetData($g_hLabelRunningTime, $sTimer) + EndIf + WEnd +EndFunc + +Func _runBMXwrap($command, $wd) + ConsoleWrite("$sBMXcommand: " & $command & @CRLF) + Local $hPid = Run('"' & @ComSpec & '" /c ' & $command, $wd, @SW_HIDE, $STDOUT_CHILD + $STDERR_CHILD) + Local $sStdErr, $sTimer + Local $iPercent = 0, $iTimer + While 1 + Sleep(500) + $sStdErr = StdoutRead($hPid) + If @error Then ExitLoop + $g_sStdErrAll &= $sStdErr + If StringLen($sStdErr) > 0 Then +;~ ConsoleWrite("StdOut: " & $sStdErr & @CRLF) + $iPercent = _GetPercent($sStdErr) + If Not @error Then $sStdErr = "" + GUICtrlSetData($Progress2, $iPercent) EndIf $iTimer = TimerDiff($g_hTimerStart) $sTimer = _Zeit($iTimer) @@ -699,6 +832,17 @@ Func _GetTime($sStdErr) Return _TimeToTicks($aTime[0], $aTime[1], $aTime[2]) EndFunc ;==>_GetTime +Func _GetPercent($sStdErr) + If Not StringInStr($sStdErr, "%") Then Return SetError(1, 0, 0) + Local $aRegExp = StringRegExp($sStdErr, "(?i)\d{1,2}\.\d%", 3) + If @error Or Not IsArray($aRegExp) Then Return SetError(2, 0, 0) + Local $sPercent = $aRegExp[0] + $sPercent = StringTrimRight($sPercent, 1) ; remove % + ConsoleWrite("Percent: " & $sPercent & @CRLF) + Return $sPercent +EndFunc + + Func _FileName($sFullPath) Local $iDelimiter = StringInStr($sFullPath, "\", 0, -1) Return StringTrimLeft($sFullPath, $iDelimiter) diff --git a/README.md b/README.md index 28794e7..3f7c1e9 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,10 @@ Provide a mxf (tested only with xdcam hd 422 op1a including 8 audio tracks) and ## Prerequisites -To build your swapper yourself you need a compiled ffmpeg that must be embedded into your swapper. Customize the following code line: +To build your swapper yourself you need a compiled ffmpeg and bmxtranswrap that must be embedded into your swapper. Customize the following code lines: `FileInstall('K:\ffmpeg\bin\ffmpeg.exe', @TempDir & "\ffmpeg.exe", $FC_OVERWRITE)` +`FileInstall('K:\bmxtranswrap\bmxtranswrap.exe', @TempDir & "\bmxtranswrap.exe", $FC_OVERWRITE)` ## Manual @@ -45,5 +46,8 @@ The new mxf file will be created in `%temp%` folder. This folder will be opened The routing example in the image above would be named `Spurkennung_1-5_2-6_3-3_4-4_5-L_6-R_7-8_8-7.mxf`. +## Insides +Wrapping with ffmpeg can't create valid v1.3 op1a mxf in ard zdf profile. This is done with bmxtranswrap. Bmxtranswrap can swap audio tracks or mute them. But it can't insert external audio. So if external audio is provided the track swapping, muting and inserting is done with ffmpeg and the mxf is rewrapped with bmxtranswrap afterwards. Else the swapping and muting is done with bmxtranswrap alone. + ## Known issues If you use only one track ot the external stereo wav file (e.g. "[R]") it breaks: "Filter channelsplit:FL has an unconnected outut". diff --git a/images/MXF-Track-Swap_muxing.png b/images/MXF-Track-Swap_muxing.png index 670d9bad2e63d0e912ce72cb2e2dfd6f85366bdf..b06c768ed99ec94af9e6c38dd86f5c5b422921f8 100644 GIT binary patch literal 8115 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 literal 8427 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 CY>KV` -- GitLab