2026年10月12日 星期一

以 ffmpeg 做 DJI Neo 空拍機 錄影檔影音合併整理 再以 LosslessCut 做編輯

最近驚訝地發現,之前因為可以自動跟飛攝影,所以買的 DJI Neo Mini Drone ,竟然從拿到試飛熟悉功能,到錄最後一個檔案,總共編號才100,全部都發生在11天之內的其中6天,然後就這樣放了2年多,影片也是最近才複製出來整理,實在是太浪費了。


因為可以手勢及遙控器操作,並不一直連接手機,這些 mp4 影片許多是沒有聲音的,有的那些則是透過手機App遙控,從手機收音即時降噪另外存成同名的 m4a 格式音檔,大多是 34kbps mono 15.63fps 單軌音訊幀率。我以常用的 LosslessCut 試著接起這些零碎影片,因為軟體設計成以清單第一個檔案的格式與軌道數合併,很大機會造成有聲音的影片,聲音軌道被放棄不合併。要逐一檢查這百個檔案實在耗時不合理,只好全部先批次整理過再作後續剪貼接合,這邊的方案是用 LosslessCut 的底層工具 ffmpeg,試錯了幾次成功保留 EXIF 資訊後,最終以下述指令做編輯準備。

前置作業:按 Win+Pause/Break 打開系統資訊,找到進階系統設定,按環境變數,在系統變數中找到Path後按編輯,然後新增,再來貼上 ffmpeg 資料夾的完整路徑。

使用方式:打開存放 DJI Neo 影片(MP4)與音檔(M4A)的資料夾,在視窗空白處,按住鍵盤的 Shift 鍵不放,同時點擊滑鼠右鍵,選擇「在此處開啟 PowerShell 視窗」(或「在此處開啟終端機」)。完整複製下方這一整段指令,貼進視窗中,然後按下 Enter。

======== 以下為 PowerShell 指令 ========
# 1. 建立存放預處理影片的全新資料夾
New-Item -ItemType Directory -Force -Path ".\ready_for_losslesscut" | Out-Null

# 2. 開始批量比對處理(加入 EXIF 複製與檔案時間戳同步)
Get-ChildItem *.mp4 | ForEach-Object {
    $baseName = $_.BaseName
    $m4aFile = ".\$baseName.m4a"
    $outFile = ".\ready_for_losslesscut\$($_.Name)"

    if (Test-Path $m4aFile) {
        # 情境 A:找到同名 m4a,複製原檔所有 EXIF 詮釋資料 (-map_metadata 0)
        ffmpeg -y -i $_.Name -i $m4aFile -c:v copy -c:a copy -map_metadata 0 $outFile 2>$null
    } else {
        # 情境 B:沒有同名 m4a,補上空白音軌並複製原檔所有 EXIF 詮釋資料
        ffmpeg -y -i $_.Name -f lavfi -i anullsrc=channel_layout=mono:sample_rate=16000 -c:v copy -c:a aac -b:a 34k -shortest -map_metadata 0 $outFile 2>$null
    }

    # 3. 如果成功生成新檔案,強行將原始檔案的時間戳(建立、修改、存取時間)複製過去
    if (Test-Path $outFile) {
        $origFile = $_.FullName
        $newFileObj = Get-Item $outFile
       
        $newFileObj.CreationTime = $_.CreationTime
        $newFileObj.LastWriteTime = $_.LastWriteTime
        $newFileObj.LastAccessTime = $_.LastAccessTime
    }
}
Write-Host "處理完成!所有檔案已完整保留原始 EXIF 與時間戳,並生成在 ready_for_losslesscut 資料夾中。" -ForegroundColor Green 
======== 以上為 PowerShell 指令 ========


雖然最近也有使用蘋果電腦,但是不喜歡 MacOS 時不時在磁碟留下隱形垃圾,所以整理照片影片,我還是回歸使用微軟PC。不過為預防萬一,還是叫 Gemini 生成了 Mac 版指令,沒實際搬檔案去試過,但應該差不多是這樣了。

在 Mac 上操作邏輯一樣,但需要將 Windows 的 PowerShell 語法換成 Mac 的 Zsh/Bash 終端機(Terminal)語法。在 Mac 系統中,我們同樣使用 -map_metadata 0 複製內部 EXIF 標籤,並利用 Mac 內建的 touch -r 指令,將原始檔案的外部修改與存取時間「複製」到新檔案上。

touch -r "$f" "$out_file":這是 Mac/Linux 系統的核心指令。它的意思是「以原始檔案 f 為基準(reference),將其建立與修改時間戳同步寫入新檔案(out_file)中」。

前置作業:要在 Mac 上也安裝好 FFmpeg(例如透過 Homebrew),此腳本便能執行。

操作步驟:打開 Mac 的 「終端機 (Terminal)」 應用程式,輸入 cd (注意 cd 後面有一個空格),然後將存放 DJI 影片與 M4A 音檔的資料夾,用滑鼠直接拖曳進終端機視窗中,再按下 Enter 切換路徑。最後完整複製下方整段指令,貼進終端機中,並按下 Enter 執行。

======== 以下為 Bash 指令 ========
# 1. 建立存放預處理影片的全新資料夾
mkdir -p ./ready_for_losslesscut

# 2. 開始批量比對處理(Zsh/Bash 語法)
for f in *.mp4; do
    # 取得不含副檔名的主檔名
    base="${f%.*}"
    m4a_file="./${base}.m4a"
    out_file="./ready_for_losslesscut/${f}"

    if [ -f "$m4a_file" ]; then
        # 情境 A:找到同名 m4a,直接進行無損影音封裝,並複製內部 EXIF (-map_metadata 0)
        ffmpeg -y -i "$f" -i "$m4a_file" -c:v copy -c:a copy -map_metadata 0 "$out_file" 2>/dev/null
    else
        # 情境 B:沒有同名 m4a,無損補上 34k Mono 空白音軌,並複製內部 EXIF
        ffmpeg -y -i "$f" -f lavfi -i anullsrc=channel_layout=mono:sample_rate=16000 -c:v copy -c:a aac -b:a 34k -shortest -map_metadata 0 "$out_file" 2>/dev/null
    fi

    # 3. 如果成功生成新檔案,使用 Mac 內建的 touch 指令,將原檔(f)的時間戳完美複製給新檔(out_file)
    if [ -f "$out_file" ]; then
        touch -r "$f" "$out_file"
    fi
done

echo "處理完成!所有檔案已完整保留原始 EXIF 與時間戳,並生成在 ready_for_losslesscut 資料夾中。"
======== 以上為 Bash 指令 ========

2026年10月11日 星期日

[info轉貼] 推廣開放原始碼的影音多媒體編碼器工具ffmpeg

就像數位照片整理多了,用過各式軟體,最後還是得擁抱 ExifTool。
最近數位影片也漸漸整理多了,是時候學習以前嫌複雜的 ffmpeg了。
在巴哈姆特找到神級推廣文,萬一以後找不到怎麼辦?請務必讓我複製一份備查!
作者:晴空和聲

【心得】推廣開放原始碼的影音多媒體編碼器工具ffmpeg

樓主 晴空和聲 jtdjdu6868
GP176 BP-

2026年9月7日 星期一

自動掛載 VeraCrypt 加密虛擬磁碟檔案(容器)的 Mac Shell 指令碼。

使用蘋果電腦以後,不能使用以前習慣的 bat 批次檔執行指令,好像變得比較麻煩不直覺,後來經過一番閱讀發現其實也還好,這邊以最近用到加密容器掛載需求為例:

步驟 1:建立自動化指令碼
打開 Mac 的 文字編輯機 App。
按下快速鍵 Shift + Cmd + T 將文字格式轉為純文字。
複製並貼上以下程式碼,存檔為 mount.sh:

步驟 2:賦予執行權限
Mac 出於安全考量,預設不允許直接執行點擊的指令碼。請打開終端機 (Terminal) 並輸入以下指令授予檔案執行權限:
chmod +x ~/Documents/mount.sh
chmod +x ~/Desktop/dismount_all.sh

步驟 3:如何一鍵執行?
如果希望像 Windows 一樣雙擊滑鼠就能執行,在 mount.sh 檔案上按右鍵選擇「取得資訊」,將「開啟檔案的應用程式」修改為「終端機.app」。

掛載預先指定加密容器
================ 以下為 mount.sh (放在文件檔案夾)範例 ================
#!/bin/bash

# 1. --- 請修改您的容器路徑與掛載名稱 ---
CONTAINER_PATH="/Users/您的用戶名/Documents/加密容器.hc"
VOLUME_NAME="VeraCrypt_Drive"
# ---------------------------------

# 2. 彈出 macOS 原生密碼輸入視窗
PASSWORD=$(osascript -e 'display dialog "請輸入 VeraCrypt 容器密碼:" default answer "" with hidden answer buttons {"取消", "確定"} default button "確定"' -e 'text returned of result' 2>/dev/null)

# 3. 如果使用者點擊取消或沒輸入,則直接退出
if [ -z "$PASSWORD" ]; then
    exit 0
fi

# 4. 使用 printf 代替 echo(防止自動加換行符號),並用 --stdin 參數代替 --password=-,相容性與穩定度更高。
# 5. 視需求選擇是否加上 --truecrypt 開啟 TrueCrypt 檔案,或使用 -m ro 開啟唯獨模式。
# 6. (使用 2>&1 將錯誤訊息存入 ERROR_MSG 變數中)
ERROR_MSG=$(printf "%s" "$PASSWORD" | /Applications/VeraCrypt.app/Contents/MacOS/VeraCrypt --text --truecrypt -m ro --non-interactive --stdin --mount "$CONTAINER_PATH" "/Volumes/$VOLUME_NAME" 2>&1)

# 7. 檢查掛載狀態 (0 代表成功)
if [ $? -eq 0 ]; then
    # 8. 成功:清除密碼、自動開啟 Finder
    unset PASSWORD
    open "/Volumes/$VOLUME_NAME"
else
    # 9. 失敗:清除密碼、將錯誤訊息用視窗彈出
    unset PASSWORD
   
    # 10. 整理錯誤訊息格式,避免換行字元與引號影響 AppleScript
    CLEAN_ERROR=$(echo "$ERROR_MSG" | tr '\n' ' ' | sed "s/\"/'/g")
   
    osascript -e "display alert \"掛載失敗\" message \"VeraCrypt 系統回報錯誤:\n\n$CLEAN_ERROR\" as critical"
fi
================ 以上為 mount.sh (放在文件檔案夾)範例 ================

一次卸載所有加密容器
================ 以下為 dismount_all.sh (放在桌面)範例 ================
#!/bin/bash

# 1. 執行全局解除掛載指令 (不帶任何路徑,代表全部彈出)
# 加上 --force 參數,可以防止某些輕微的系統佔用導致彈出失敗
ERROR_MSG=$(/Applications/VeraCrypt.app/Contents/MacOS/VeraCrypt --text --non-interactive --dismount --force 2>&1)

# 檢查卸載狀態 (0 代表成功)
if [ $? -eq 0 ]; then
    # 2. 成功:跳出通知
    osascript -e 'display alert "全部解除掛載成功" message "所有 VeraCrypt / TrueCrypt 容器已安全關閉並全數登出。" buttons {"確定"} default button "確定"'
else
    # 3. 失敗:將錯誤訊息彈出
    CLEAN_ERROR=$(echo "$ERROR_MSG" | tr '\n' ' ' | sed "s/\"/'/g")
   
    # 如果其實本來就沒有掛載任何東西,VeraCrypt 會報錯,這裡做個防呆提示
    if [[ "$CLEAN_ERROR" == *"No volume mounted"* ]]; then
        osascript -e 'display alert "提示" message "目前系統中沒有任何已掛載的加密容器。" buttons {"確定"}'
    else
        osascript -e "display alert \"全部解除掛載失敗\" message \"無法完全關閉所有磁碟。\n\n系統回報:$CLEAN_ERROR\" as critical"
    fi
fi
================ 以上為 dismount_all.sh (放在桌面)範例 ================

這樣一番設定後,就可以直接在 Macbook 點二下執行想要的動作了。