2

我对 python 比较陌生,所以如果这是一个之前已经回答过的问题,请耐心等待。我正在编写一个 python 脚本来将几个视频文件合并在一起,我试图在线搜索答案但无济于事。我想知道我是否可以在不使用 ffmpeg 的情况下编写一个 python 脚本,而只是为程序编写纯 python 代码。我已经尝试过这样的事情,但它并没有真正起作用

fo=open("outfile","wb")
fo.write(open("infile1").read())
fo.write(open("infile2").read())
fo.close()
4

3 回答 3

3

我不确定,您是否可以将一个视频文件附加到另一个。每个视频文件都有特定的格式,包括标题、曲目等。看看http://en.wikipedia.org/wiki/MPEG_transport_stream。但是,使用 ffmpeg,您可以这样做:

ffmpeg -i "concat:input1.mpg|input2.mpg|input3.mpg" -c copy output.mpg

祝你今天过得愉快 ;)

于 2013-07-16T09:17:11.370 回答
2

我的用例需要将分布在 16 个文件夹中的一堆 .mp3 文件连接到每个文件夹一个 .mp3 中。ffmpeg.orgffmpeg-python上的文档被发现有些缺乏或令人困惑......

我希望能够创建一个 ffmpeg 对象,然后将一个列表或将单个路径对象迭代到 ffmpeg 的输入中,然后在输入对象上运行 concat,然后输出到一个目的地,但ffmpeg.input(<FILE LIST>).concat(acodec='copy').output(<OUTFILE>).run()最终成为一个巨大的失败球.. . 直到我遇到@CCfVssZijV2X的帖子,其中包含 concat 输入格式,它为我破解了整个事情。

下面的脚本将基本路径作为输入。假设基本路径包含包含多个音频文件的文件夹,这些文件将作为基本路径中的文件夹名称连接到每个文件夹中的单个 .mp3 中。

如果基本路径仅包含一个文件夹,则将文件夹批处理直接发送到 combine_audio,否则将批处理列表发送到多处理功能,该功能将每个批处理拆分为您拥有或可用的内核数量。

虽然我确信我与 python 包装器有关的一些问题的原因与我对 ffmpeg 的无知和不熟悉有关,但我希望这可以帮助某人,或者让他们开始为他们的用例走上正确的道路。

from concurrent.futures import ProcessPoolExecutor
from pathlib import Path as p
from os import cpu_count
import ffmpeg

class FFConcat:

    def __init__(self, path, check_files=False):

        self.check_files = check_files
        self.path = p(path)
        self.cores = cpu_count()
        self.batches = []

    def file_check(self):
        '''
        Optional:
        Iterates over folders in path, renames with leading zero for sorting if missing.
        '''
        for folder in sorted(self.path.iterdir()):
            # Folder names were originally "Folder Name - [Disk 1]"
            disk_number = folder.stem.split()[-1].strip(']')
            if len(disk_number) == 1:
                folder.rename('{}/Folder Name - Disk 0{}'.format(self.path, disk_number))
            elif len(disk_number) == 2:
                folder.rename('{}/Folder Name - Disk {}'.format(self.path, disk_number))

    def file_batch(self):
        '''
        Iterates over folders in path creating a list. Converts list into string format
        which is combined with resulting output filename in a dict and added to
        batch list.
        '''
        print('Batching audio files by folder.')
        for folder in sorted(self.path.iterdir()):
            # Use folder names as concat output name for final file.
            outfile = (self.path/'{}.mp3'.format(folder.stem)).as_posix()
            tracks = []
            # Create a list of sorted tracks in folder.
            for track in sorted(folder.iterdir()):
                tracks.append(track.as_posix())
            print('Located {} audio files in \"{}\"'.format(len(tracks), folder.stem))
            # Format file list in string format which ffmpeg will accept via input.
            file_list = '|'.join(_ for _ in tracks)
            # Generate list of dictionaries containing the file list and output filemame
            self.batches.append({
                                'file_list': file_list,
                                'outfile': outfile
                                })

    def combine_audio(self, batch):
        '''
        Input: single dictionary containing a string formatted file list for each folder
        and output filename. Converts list into ffmpeg input concat object. Runs object
        with audio codec copy concatenating files within folder into single file.
        '''
        print('Starting concat for: {}'.format(batch['outfile']))
        tracks = ffmpeg.input('concat:{}'.format(batch['file_list']))
        tracks.output(batch['outfile'], acodec='copy').run()
        print('Completed concat for: {}'.format(batch['outfile']))

    def mp(self, function, iterable):
        '''
        Input: combine_audio function and batch list.
        Sets max workers depending on iterable length and core count.
        '''
        if len(iterable) >= self.cores:
            workers = self.cores
        elif len(iterable) < self.cores:
            workers = len(iterable)
        with ProcessPoolExecutor(max_workers=workers) as p:
            p.map(function, iterable)

    def run(self):

        if self.check_files:
            self.file_check()

        self.file_batch()

        if len(self.batches) == 1:
            print('One batch found. Sending directly to concatenator.')
            self.combine_audio(self.batches[0])
        elif len(self.batches) > 1:
            print('Sending {} batches to multi-processing.'.format(len(self.batches)))
            self.mp(self.combine_audio, self.batches)

concat = FFConcat(path='Base path containing folders with tracks')
concat.run()

最后需要连接一些视频,并且看到其中一条评论询问了这一点,这是我想出的将两个大文件连接在一起的快速而肮脏的方法。

from pathlib import Path as p
import ffmpeg

# point basepath to input directory where videos are located. ideally without anything else.
basepath = p('/video_input_directory')

# path iterator to grab input files in basepath, and create a posix filename list.
# you can keep, modify, or drop the suffix filter.
input_files = sorted([
                        _.as_posix() for _ in basepath.iterdir()
                        if _.is_file() and _.suffix == '.mp4'
                        ])

# set output filename
outFile = basepath / 'concated.mp4'

# create file object that will contain files for ffmpeg to concat
input_files_path = basepath / 'input_files.txt'

# iterate over sorted posix files in list, and dump to file in the required format
with input_files_path.open('w') as f:
    for file in input_files:
        f.write('file \'{}\'\n'.format(file))

# this seems to be the proper concat input, with the path containing the list
# of files for ffmpeg to concat, along with the format parameter, and safe, if i
# read the docs correctly, is default/optional
ffInput = ffmpeg.input(input_file_path.as_posix(), format='concat', safe=0)

# output parameters
params =    {
            'c': 'copy'
            }
# input stream -> output stream with output filename and expanded params
ffOutput = ffInput.output(ouFile.as_posix(), **params)

# make ffmpeg quiet
ffOutput = ffOutput.global_args('-loglevel', 'error')

# something, something, run.
ffOutput.run(overwrite_output=True)

连接视频时有很多 *,所以一定要查看ffmpeg 网站上的 concat 部分,以及这个 ffmpeg concat wiki

于 2019-03-22T20:25:57.250 回答
0

我想知道我是否可以编写一个 python 脚本而不使用 ffmpeg 只是纯 python

不,您需要了解编解码器才能组合视频内容(包括音轨),然后将其打包到适当的容器中。这不是一项微不足道的任务,这就是为什么有库可以自动化它的原因。

于 2013-07-16T09:23:43.487 回答