使用 ffmpeg 将 DTS 音轨转换为 AC3 并重新添加至 MKV?

使用 ffmpeg 将 DTS 音轨转换为 AC3 并重新添加至 MKV?

我的家庭音响系统仅支持杜比 (AC3),不支持 DTS。因此,如果我想要 5.1 环绕声,我会ffmpeg像这样使用:

ffmpeg -i my_movie.mkv -map 0 -vcodec copy -scodec copy -acodec ac3 -b:a 640k my_movie_ac2.mkv

这会创建一个包含 AC3 音轨而非 DTS 的单独文件。我该如何将 AC3 流作为附加音轨添加回 MKV?我想保留 DTS 音轨,但不想有两个单独的 MKV 文件。

答案1

使用

ffmpeg -i my_movie.mkv -map 0:v -map 0:a:0 -map 0:a -map 0:s -c:v copy -c:a copy -c:s copy -c:a:0 ac3 -b:a:0 640k my_movie_ac2.mkv

使 ffmpeg 处理第一个音频流的方式不同于其他所有音频流有关如何应用流说明符的指南。

答案2

以下是代码

ffmpeg -i INPUT_VID.mkv -map 0:v -c:v copy -map 0:a:0 -c:0:a:0 copy -disposition:a:0 1 -map 0:a:0 -c:0:a:1 ac3 -disposition:a:1 0 OUTPUT_VID.mkv
  • -map 0:v -c:v copy 复制视频
  • -map 0:a:0 -c:0:a:0 copy -disposition:a:0 1将原始音频复制为第一个定位音频 (-c:a:0) 并将其设为默认值 (配置 1)
  • -map 0:a:0 -c:0:a:1 ac3 -disposition:a:1 0将音频转换为 ac3 作为第二定位音频 (-c:a:1),并删除此位置的所有默认标志 ​​(配置 0)

#ffmpeg #音频

答案3

您必须考虑转换所有音轨。

由于每个文件的命令根据音轨数量而不同,我创建了一个 python 脚本来创建 ffmpeg 命令并执行它。

列出音频/字幕轨道:

python3 allAudioToAC3.py scan -i /root/myfile.mkv

将所有音轨转换为 AC3:

python3 allAudioToAC3.py convert -i /root/input.mkv -o /root/output.mkv

或者将所有音轨转换为 AC3 并删除输入文件:

python3 allAudioToAC3.py convert -i /root/input.mkv -o /root/output.mkv -r

Python3脚本allAudioToAC3.py

#!/usr/bin/env python3

import os
import sys
import json
import subprocess
from argparse import ArgumentParser

cli = ArgumentParser()
subparsers = cli.add_subparsers(dest="subcommand")

def argument(*name_or_flags, **kwargs):
    """Properly format arguments to pass to the subcommand decorator"""
    if "default" in kwargs and "help" in kwargs:
        kwargs["help"] += " (default: {[default]})".format(kwargs)
    return (list(name_or_flags), kwargs)

def subcommand(args=[], parent=subparsers):
    """Decorator to define a new subcommand in a sanity-preserving way."""
    def decorator(func):
        name = func.__name__
        if name.endswith("_"):
            name = name[:-1]
        parser = parent.add_parser(name, description=func.__doc__)
        for arg in args:
            parser.add_argument(*arg[0], **arg[1])
        parser.set_defaults(func=func)
    return decorator

@subcommand([
    argument("-i", "--input", required=True, help="Input file")])
def scan(args):
    """Scan/Display all audio and subtitle"""
    audio_flag = False
    ffprobe_cmd = "ffprobe -hide_banner -show_streams -print_format json " + args.input
    process = subprocess.Popen(ffprobe_cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True).communicate()
    output = json.loads(process[0])

    for stream in output["streams"]:
        if stream['codec_type'] == 'audio':
            audio_flag = True
            break;

    if audio_flag:
        print("audio present in the file")
    else:
        print("audio not present in the file")
        sys.exit(1)

    for stream in output["streams"]:
        if stream['codec_type'] == 'audio':
            print('--------------------------')
            print('AUDIO: Codec Format :', stream['codec_long_name'], stream['codec_name'])
            try:
                print('AUDIO: Language :', stream['tags']['language'])
            except:
                pass
            print('AUDIO: Piste index :', stream['index'])

        if stream['codec_type'] == 'subtitle':
            print('--------------------------')
            print('SUBTITLE: Codec Format :', stream['codec_long_name'], stream['codec_name'])
            try:
                print('SUBTITLE: Language :', stream['tags']['language'])
            except:
                pass
            print('SUBTITLE: Piste index :', stream['index'])

@subcommand([
    argument("-i", "--input", required=True, help="Input file"),
    argument("-o", "--output", required=True, help="Output File"),
    argument("-r", "--remove", action='store_true', help="Remove Input file")])
def convert(args):
    """Convert all audio to AC3"""
    audio_flag = False
    ffprobe_cmd = "ffprobe -hide_banner -show_streams -print_format json " + args.input
    process = subprocess.Popen(ffprobe_cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True).communicate()
    output = json.loads(process[0])

    for stream in output["streams"]:
        if stream['codec_type'] == 'audio':
            audio_flag = True
            break;

    if audio_flag:
        print("audio present in the file")
    else:
        print("audio not present in the file")
        sys.exit(1)

    pistes = []
    i = 0
    subtitle = ""
    for stream in output["streams"]:
        if stream['codec_type'] == 'audio':
            print('--------------------------')
            print('AUDIO: Codec Format :', stream['codec_long_name'], stream['codec_name'])
            try:
                print('AUDIO: Language :', stream['tags']['language'])
            except:
                pass
            print('AUDIO: Piste index :', stream['index'])
            pistes.append('-c:a:{} ac3'.format(i))
            i = i + 1

        if stream['codec_type'] == 'subtitle':
            print('--------------------------')
            print('SUBTITLE: Codec Format :', stream['codec_long_name'], stream['codec_name'])
            try:
                print('SUBTITLE: Language :', stream['tags']['language'])
            except:
                pass
            print('SUBTITLE: Piste index :', stream['index'])
            subtitle = " -c:s copy"


    audio = ' '.join(pistes)
    cmd = "ffmpeg -i {} -map 0 -c:v copy {}{} {}".format(args.input, audio, subtitle, args.output)
    print(cmd)
    os.system(cmd)

    if args.remove:
        print('Remove Input file:', args.input)
        os.remove(args.input)


if __name__ == "__main__":
    args = cli.parse_args()
    if args.subcommand is None:
        cli.print_help()
        sys.exit()

    args.func(args)

答案4

查看 MKVToolNix:https://mkvtoolnix.download/

它可以让您更改 mkv 文件,例如添加/删除音频流。仍然是一个两步过程,但如果需要,可以将它们编写成一个脚本并一起进行调用。

相关内容