流复制所有流

流复制所有流

我正在尝试使用 ffmpeg 对 Matroska 文件中的视频流重新编码以节省空间,同时保持所有字幕不变。我想编写一个通用命令,无需指定确切的流编号即可工作。现在我不知道如何让 ffmpeg 选择它的默认视频流和默认音频流,然后是所有字幕。

我正在使用的当前输入文件具有这些流,但其他文件将具有不同的流。

    [lavf] stream 0: video (mpeg2video), -vid 0
    [lavf] stream 1: audio (ac3), -aid 0, -alang eng, Surround 5.1
    [lavf] stream 2: audio (ac3), -aid 1, -alang fre, Surround 5.1
    [lavf] stream 3: audio (ac3), -aid 2, -alang ita, Surround 5.1
    [lavf] stream 4: audio (ac3), -aid 3, -alang spa, Surround 5.1
    [lavf] stream 5: audio (ac3), -aid 4, -alang eng, Stereo
    [lavf] stream 6: subtitle (dvdsub), -sid 0, -slang eng
    [lavf] stream 7: subtitle (dvdsub), -sid 1, -slang fre
    [lavf] stream 8: subtitle (dvdsub), -sid 2, -slang ita
    [lavf] stream 9: subtitle (dvdsub), -sid 3, -slang spa
    [lavf] stream 10: subtitle (dvdsub), -sid 4, -slang ara
    [lavf] stream 11: subtitle (dvdsub), -sid 5, -slang dan
    [lavf] stream 12: subtitle (dvdsub), -sid 6, -slang dut
    [lavf] stream 13: subtitle (dvdsub), -sid 7, -slang fin
    [lavf] stream 14: subtitle (dvdsub), -sid 8, -slang ice
    [lavf] stream 15: subtitle (dvdsub), -sid 9, -slang nor
    [lavf] stream 16: subtitle (dvdsub), -sid 10, -slang por
    [lavf] stream 17: subtitle (dvdsub), -sid 11, -slang swe
    [lavf] stream 18: subtitle (dvdsub), -sid 12, -slang fre
    [lavf] stream 19: subtitle (dvdsub), -sid 13, -slang ita
    [lavf] stream 20: subtitle (dvdsub), -sid 14, -slang spa

我尝试过的命令:

ffmpeg -i IN.mkv -c:v libx264 -threads 4 -speed 1 -f matroska OUT.mkv

结果:一个视频流,一个音频流,无字幕流

ffmpeg -i IN.mkv -c:v libx264 -threads 4 -speed 1 -f matroska -c:s copy OUT.mkv

结果:一个视频流,一个音频流,一个字幕流

ffmpeg -i IN.mkv -c:v libx264 -threads 4 -speed 1 -f matroska -map 0 OUT.mkv

结果:所有视频,全部音频,所有字幕。

ffmpeg -i IN.mkv -c:v libx264 -threads 4 -speed 1 -f matroska -c:s copy -map 0:s OUT.mkv

结果:没有视频,没有音频,所有字幕。

据我从手册中可以看出,-c:s copy应该复制所有流,而不仅仅是默认流,但它不会。也许这是一个错误?

为了澄清一下,我所追求的是结果:一伏想法,一个音频和所有的字幕。

答案1

流选择 默认行为只为每种类型的流选择一个流,因此具有多个音频流的输入将创建具有一个音频流的输出。要禁用此行为并手动选择所需的流,请使用-map选项

这些例子-c copy用于流复制(重新复用)从输入到输出。不会发生重新编码。

流复制所有流

ffmpeg -i input -map 0 -c copy output

第一个视频流,第二个音频流,所有字幕

ffmpeg -i input -map 0:v:0 -map 0:a:1 -map 0:s -c copy output

第三个视频流,所有音频流,无字幕

本示例使用负映射排除字幕。

ffmpeg -i input -map 0:v:2 -map 0:a -map -0:s -c copy output

从多个输入中选择流

所有视频均来自输入 0,所有音频均来自输入 1:

ffmpeg -i input0 -i input1 -map 0:v -map 1:a -c copy output

答案2

#!/bin/bash
# 从给定目录中的每个 MKV 文件中提取旧格式视频轨道并将其转码为例如 x265
# 为您的目的扩展;-) 我已经运行这个脚本一年多了。
回显 MKV:迁移
echo "| no args : 扫描候选目录树"
echo "| dir : 扫描该目录"
echo "| . -c : 将这些候选中的视频轨道转换为 H.265 (x265)"
echo "| .-c -r : 转换并重新混合为新的结果视频"
echo "\ . -c -r -k : 并保留中间视频文件(默认情况下不是)"
回声“”
日期
echo 读取 MKV 文件的所有目录,并验证其中是否有 Mpeg-4p2、H264、XVid、DivX 或 H263 轨道。
echo 如果是,则会用 mkvextract 提取并用 ffmpeg 转换为 H265。
echo 如果重新混合,原文件将命名为.old.mkv,新文件将保留原文件名称,后缀为.x265.mkv。
echo 通过使用 mkvmerge 重新混合,新的视频轨道将被集成,而原始的旧格式轨道则不会。
echo "(参见: ffmpeg bla bla bla -d \!0 trackno 如果轨道 0 是旧的视频格式,它将被 -d 跳过)"
回声。
vidxt=“mp4”
vidco =“libx265”
H264=“”
H264="(H.264)|H264|(MPEG-4p10)|"
CRF =“25”
VIDRATE=“1500k”
#如果有 4 个核心,则有 400% 可用。将您的进程限制为 65%,例如
CPULIM=240
#SCALE=“-vf 比例=1280:720”
#RATE=“-r 23.976216”

# 如果没有给出目录,则在本地目录中工作
如果[“$1”==“”];然后
  目录=“。”
  转换为“”
  多雷穆克斯=“”
  保持=“”
别的
  目录=“$1”
  转换=$2
  doremux=$3
  保留=$4
# 我首先运行这个脚本来摆脱真正旧的格式......
如果 [ “$H264” == “ ” ]; 然后
  echo“不扫描 H.264 视频轨道。”
别的
  echo "同时扫描 H.264 视频轨道:"$H264

# 获取该目录及其子目录中的所有 MKV 文件
查找“$DIR”-type f-name '*.mkv' |排序|读取文件名时
  # 找出哪些曲目包含字幕
  # echo 检查:$文件名
  坎=0
  
  mkvmerge -i "$文件名" | grep '视频' |读取子行时
    候选人=`回声 $subline | egrep -o $H264"(avc1)|(XVID)|(DX50)|MPEG-4p2"`
    #echo $文件名.$子行
    if [ "$candidate" != "" ];然后
        # Grep 视频/音频轨道的编号
        tracknumber=`回声 $subline | egrep -o "[0-9]{1,2}" |egrep -o "[0-9]{1,2}" |头-1`
        #echo " EVAL : " $candidate " trk:" $tracknumber " cand: " $cand

        如果 [ $cand != 1 ];然后
        回显“|”
        echo $文件名" : " $subline " : " $tracknumber
        MYDAT=$(ls -l --full-time "${filename}" |gawk -F ' ' '{ print $6" "$7 }' | gawk -F. '{ print $1 }')
        echo " | 原始日期: "$MYDAT
        坎=1
        别的
        echo " /--下一首"
        回显“|” `日期`
        echo " | 候选人: [$candidate]"

        # 获取字幕的基本名称
        基本文件名=${文件名%.*}
        echo " \-- 视频: "$subline" ($basefilename)"
        
        如果[“$doconvert”==“-c”];然后
        # 将曲目提取到 .tmp 文件
        echo " -- 提取 $tracknumber:$basefilename.vid.tmp (平均 2 分钟) "
            `mkvextract 跟踪 "$filename" $tracknumber:"$basefilename.vid.tmp" >>/dev/null 2>&1`
        `chmod g+rw "$basefilename.vid.tmp"`
        # 进行 FFMPEG 转换
        回显“--”`日期`
        echo " -- FFMpeg 通过 $vidco 将 $basefilename.vid.tmp 转换为 $vidxt (平均 2 小时)"
# echo ` ffmpeg -i "$basefilename.vid.tmp" $RATE -c:v:0 $vidco -crf $CRF -b:v:0 $VIDRATE $SCALE "$basefilename.$tracknumber.$vidxt"` > /dev/null 2>&1
        `cpulimit -f --limit=$CPULIM -- ffmpeg -i "$basefilename.vid.tmp" $RATE -c:v:0 $vidco -crf $CRF -b:v:0 $VIDRATE $SCALE "$basefilename .$tracknumber.$vidxt" >/dev/null 2>&1`
        如果[“$keep”==“”];然后
            `rm "$basefilename.vid.tmp" >/dev/null 2>&1`
        if [ "$doremux" == "-r" ];然后
            回显“--”`日期`
            `mv "$filename" "$basefilename".old.mkv >/dev/null 2>&1`
            echo " -- 混合 $filename 而不使用轨道 $tracknumber 但使用 $vidxt。(平均 4 分钟)"
            mkvmerge -o "$basefilename.x265.mkv" -d \!$tracknumber "$basefilename.old.mkv" "$basefilename.$tracknumber.$vidxt" >>/dev/null 2>&1
            如果[“$keep”==“”];然后
                `rm "$basefilename.$tracknumber.$vidxt" >/dev/null 2>&1`
            touch --date="$MYDAT" "$basefilename.x265.mkv" >>/dev/null 2>&1
  完毕
完毕

相关内容