我将从 twitch 中抓取剪辑并将它们合并以创建单个视频文件。
我已经弄清楚了抽搐剪辑链接的抓取(但我只得到 16-20 个视频,因为我需要用 Selenium 滚动,但我真的不介意,如果你有一个可行的解决方案,然后就它做出一个答案)而且也很简单合并视频。
我正在抓取以下链接:
#!/usr/bin/python3.9
import bs4
import requests
import time
from datetime import datetime
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
# Initialize driver and run it headless
options = Options()
options.headless = True
driver = webdriver.Firefox(options=options)
def extract_source(url):
agent = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0"}
source=requests.get(url, headers=agent).text
return source
def extract_data(source):
soup=bs4.BeautifulSoup(source, 'html.parser')
names=soup.find_all('a', attrs={'data-a-target':'preview-card-image-link'})
return names
driver.get('https://www.twitch.tv/directory/game/League%20of%20Legends/clips?range=24hr')
# I wait 3 seconds for the clips to get pulled in
# I'd like here to scroll down a bit so i can scrape more clips, but even after i tried some solutions my firefox(was debugging in GUI mode, not headless as it is now) wasnt scrolling
time.sleep(3)
extract_links=extract_data(driver.page_source)
for a in extract_links:
print(a.get('href'))
driver.quit()
# I tried scrolling using this but didnt work, not sure why
# this script is supposed to scroll until youre at the end of the page
# SCROLL_PAUSE_TIME = 0.5
# # Get scroll height
# last_height = driver.execute_script("return document.body.scrollHeight")
# for i in range(3):
# # Scroll down to bottom
# driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# # Wait to load page
# time.sleep(SCROLL_PAUSE_TIME)
# # Calculate new scroll height and compare with last scroll height
# new_height = driver.execute_script("return document.body.scrollHeight")
# if new_height == last_height:
# break
# last_height = new_height
使用 ffmpeg 下载(使用 youtube-dl)后,我将视频合并在一起:ffmpeg -safe 0 -f concat -segment_time_metadata 1 -i videos.txt -vf select=concatdec_select -af aselect=concatdec_select,aresample=async=1 out.mp4
其中videos.txt如下:file 'video_file1.mp4'
file 'video_file2.mp4'
...
我真的找不到关于如何添加水印的答案(每个视频都不同,尽管我发现 this 它没有解释如何为单个视频添加唯一的水印,但为两个视频添加相同的水印)而无需渲染每个每个视频两次,但一次完成。我想我偶然发现了一些制作
videos.txt
的人。如下,目的是为每个视频添加额外的选项:file 'video_file1.mp4'
option 1(for video_file1.mp4)
option 2(for video_file1.mp4)
file 'video_file2.mp4'
option 1(for video_file2.mp4)
option 2(for video_file2.mp4)
...
这是否适用于每个视频的唯一水印(假设水印被命名为 video_file1.png,...意思与视频相同,水印也是透明的,以防需要更多配置)
最佳答案
您可以通过链接 FFmpeg 过滤器来解决它(使用 filter_complex
描述的 here )。
语法令人困惑但易于管理......
例如,我选择创建合成输入文件,而不是为 WEB 下载视频(它使示例更具重现性)。
首先构建 3 个合成视频文件和 3 个合成水印图像(稍后用作输入):
import subprocess as sp
import shlex
vid1 = 'in1.mp4'
vid2 = 'in2.mp4'
vid3 = 'in3.mp4'
in_videos = [vid1, vid2, vid3]
watermark1 = 'waterMark1.png'
watermark2 = 'waterMark2.png'
watermark3 = 'waterMark3.png'
watermarks = [watermark1, watermark2, watermark3]
out_video = 'output.mp4'
n = len(in_videos)
sp.run(shlex.split(f'ffmpeg -y -f lavfi -i testsrc=size=320x240:rate=1 -f lavfi -i sine=frequency=300 -c:v libx264 -c:a aac -ar 22050 -t 5 {vid1}'))
sp.run(shlex.split(f'ffmpeg -y -f lavfi -i testsrc=size=320x240:rate=1 -f lavfi -i sine=frequency=400 -c:v libx264 -c:a aac -ar 22050 -t 5 {vid2}'))
sp.run(shlex.split(f'ffmpeg -y -f lavfi -i testsrc=size=320x240:rate=1 -f lavfi -i sine=frequency=500 -c:v libx264 -c:a aac -ar 22050 -t 5 {vid3}'))
sp.run(shlex.split(f'ffmpeg -y -f lavfi -i mandelbrot=rate=1:size=64x64 -t 1 {watermark1}'))
sp.run(shlex.split(f'ffmpeg -y -f lavfi -i cellauto=rate=1:size=64x64 -t 1 {watermark2}'))
sp.run(shlex.split(f'ffmpeg -y -f lavfi -i life=rate=1:size=64x64:mold=10:r=100:ratio=0.1:death_color=blue:life_color=#00ff00 -frames:v 1 {watermark3}'))
现在我们要构建一个命令,如下所示:
sp.run(shlex.split('ffmpeg -y -i in1.mp4 -i in2.mp4 -i in3.mp4 -i waterMark1.png -i waterMark2.png -i waterMark3.png -filter_complex "'
'[0:v:0][3:v]overlay=10:main_h-overlay_h-10[v0];'
'[1:v:0][4:v]overlay=10:main_h-overlay_h-10[v1];'
'[2:v:0][5:v]overlay=10:main_h-overlay_h-10[v2];'
'[v0][0:a:0][v1][1:a:0][v2][2:a:0]concat=n=3:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" '
'-vcodec libx264 -crf 17 -pix_fmt yuv420p -acodec aac -ar 22050 output.mp4'))
该命令覆盖水印并连接带水印的视频。可以使用几个 for 循环以编程方式构建命令:
cmd = 'ffmpeg -y '
# 'ffmpeg -y -i in1.mp4 -i in2.mp4 -i in3.mp4 '
for vid in in_videos:
cmd += '-i ' + vid + ' '
# ffmpeg -y -i in1.mp4 -i in2.mp4 -i in3.mp4 -i waterMark1.png -i waterMark2.png -i waterMark3.png
for watermark in watermarks:
cmd += '-i ' + watermark + ' '
# ffmpeg -y -i in1.mp4 -i in2.mp4 -i in3.mp4 -i waterMark1.png -i waterMark2.png -i waterMark3.png -filter_complex "
cmd += '-filter_complex "'
for i in range(n):
cmd += f'[{i}:v:0][{i+n}:v]overlay=10:main_h-overlay_h-10[v{i}];' # [0:v:0][3:v]overlay=10:main_h-overlay_h-10[v0];
for i in range(n):
cmd += f'[v{i}][{i}:a:0]' # [v0][0:a:0]
cmd += f'concat=n={n}:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" -vcodec libx264 -crf 17 -pix_fmt yuv420p -acodec aac -ar 22050 {out_video}' # concat=n=3:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" output.mp4'
这是一个完整的(可执行的)代码示例:
import subprocess as sp
import shlex
# Input video files
vid1 = 'in1.mp4'
vid2 = 'in2.mp4'
vid3 = 'in3.mp4'
in_videos = [vid1, vid2, vid3]
# Input watermark images
watermark1 = 'waterMark1.png'
watermark2 = 'waterMark2.png'
watermark3 = 'waterMark3.png'
watermarks = [watermark1, watermark2, watermark3]
out_video = 'output.mp4' # Output file name
n = len(in_videos)
# Build synthetic input files for testing (synthetic video with synthetic audio)
sp.run(shlex.split(f'ffmpeg -y -f lavfi -i testsrc=size=320x240:rate=1 -f lavfi -i sine=frequency=300 -c:v libx264 -c:a aac -ar 22050 -t 5 {vid1}'))
sp.run(shlex.split(f'ffmpeg -y -f lavfi -i testsrc=size=320x240:rate=1 -f lavfi -i sine=frequency=400 -c:v libx264 -c:a aac -ar 22050 -t 5 {vid2}'))
sp.run(shlex.split(f'ffmpeg -y -f lavfi -i testsrc=size=320x240:rate=1 -f lavfi -i sine=frequency=500 -c:v libx264 -c:a aac -ar 22050 -t 5 {vid3}'))
sp.run(shlex.split(f'ffmpeg -y -f lavfi -i mandelbrot=rate=1:size=64x64 -t 1 {watermark1}'))
sp.run(shlex.split(f'ffmpeg -y -f lavfi -i cellauto=rate=1:size=64x64 -t 1 {watermark2}'))
sp.run(shlex.split(f'ffmpeg -y -f lavfi -i life=rate=1:size=64x64:mold=10:r=100:ratio=0.1:death_color=blue:life_color=#00ff00 -frames:v 1 {watermark3}'))
# We want to get to the following command:
#sp.run(shlex.split('ffmpeg -y -i in1.mp4 -i in2.mp4 -i in3.mp4 -i waterMark1.png -i waterMark2.png -i waterMark3.png -filter_complex "'
# '[0:v:0][3:v]overlay=10:main_h-overlay_h-10[v0];'
# '[1:v:0][4:v]overlay=10:main_h-overlay_h-10[v1];'
# '[2:v:0][5:v]overlay=10:main_h-overlay_h-10[v2];'
# '[v0][0:a:0][v1][1:a:0][v2][2:a:0]concat=n=3:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" '
# '-vcodec libx264 -crf 17 -pix_fmt yuv420p -acodec aac -ar 22050 output.mp4'))
# Build ffmpeg command with arguments as a long string
cmd = 'ffmpeg -y '
# 'ffmpeg -y -i in1.mp4 -i in2.mp4 -i in3.mp4 '
for vid in in_videos:
cmd += '-i ' + vid + ' '
# ffmpeg -y -i in1.mp4 -i in2.mp4 -i in3.mp4 -i waterMark1.png -i waterMark2.png -i waterMark3.png
for watermark in watermarks:
cmd += '-i ' + watermark + ' '
# ffmpeg -y -i in1.mp4 -i in2.mp4 -i in3.mp4 -i waterMark1.png -i waterMark2.png -i waterMark3.png -filter_complex "
cmd += '-filter_complex "'
for i in range(n):
cmd += f'[{i}:v:0][{i+n}:v]overlay=10:main_h-overlay_h-10[v{i}];' # [0:v:0][3:v]overlay=10:main_h-overlay_h-10[v0];
for i in range(n):
cmd += f'[v{i}][{i}:a:0]' # [v0][0:a:0]
cmd += f'concat=n={n}:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" -vcodec libx264 -crf 17 -pix_fmt yuv420p -acodec aac -ar 22050 {out_video}' # concat=n=3:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" output.mp4'
# Execute FFmpeg
sp.run(shlex.split(cmd))
笔记:
shlex.split
将字符串拆分为列表不是最佳选择。我使用该解决方案是因为我希望该命令看起来像一个可执行命令行(对于不使用 Python 的 FFmpeg 用户来说很熟悉)。
几个示例视频帧:
关于python - 将视频与具有额外属性的 ffmpeg(或替代品)合并(叠加),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68167642/