【发布时间】:2020-04-08 01:38:21
【问题描述】:
我想生成一个特定大小的空白(黑色、白色、内容无关)MP4 视频,例如 50 MB。如何在 python 中或使用任何其他工具执行此操作?
我已经四处搜索,但只获得了代码 sn-ps 来生成特定尺寸的视频。
【问题讨论】:
标签: python-3.x ffmpeg moviepy
我想生成一个特定大小的空白(黑色、白色、内容无关)MP4 视频,例如 50 MB。如何在 python 中或使用任何其他工具执行此操作?
我已经四处搜索,但只获得了代码 sn-ps 来生成特定尺寸的视频。
【问题讨论】:
标签: python-3.x ffmpeg moviepy
您可以创建一个较短的文件并在文件末尾添加零填充。
关键是将“moov atom”放在文件的开头。
使用 FFmpeg 生成合成(灰色)视频:
ffmpeg -y -f lavfi -i testsrc=size=1920x1080:rate=1 -vf hue=s=0 -vcodec libx264 -preset superfast -tune zerolatency -pix_fmt yuv420p -t 1000 -movflags +faststart vid.mp4
你可以使用 Python 子进程模块:
sp.run('ffmpeg -y -f lavfi -i testsrc=size=1920x1080:rate=1 -vf hue=s=0 -vcodec libx264 -preset superfast -tune zerolatency -pix_fmt yuv420p -t 1000 -movflags +faststart vid.mp4')
用零填充文件,使文件大小正好为 50 MB。
这里是 Python 代码:
import subprocess as sp
import os
# Generate synthetic pattern.
# Make the pattern gray: https://davidwalsh.name/convert-video-grayscale
# Place the moov atom at the beginning of the file: https://superuser.com/questions/606653/ffmpeg-converting-media-type-aswell-as-relocating-moov-atom
# Use superfast preset and tune zerolatency for all frames to be key frames https://lists.ffmpeg.org/pipermail/ffmpeg-user/2016-January/030127.html (not a must)
# Make the file much smaller than 50MB.
sp.run('ffmpeg -y -f lavfi -i testsrc=size=1920x1080:rate=1 -vf hue=s=0 -vcodec libx264 -preset superfast -tune zerolatency -pix_fmt yuv420p -t 1000 -movflags +faststart vid.mp4')
# Add zero padding to the end of the file
# https://stackoverflow.com/questions/12768026/write-zeros-to-file-blocks
stat = os.stat('vid.mp4')
with open('vid.mp4', 'r+') as of:
of.seek(0, os.SEEK_END)
of.write('\0' * (50*1024*1024 - stat.st_size))
of.flush()
如果您希望文件大小约为 50MB,您可以设置比特率和时间。
比特大小将是比特率*时间。
见How to force Constant Bit Rate using FFMPEG
注意:测试模式有一个小问题——它太“可压缩”了,所以我们需要设置一个非常小的比特率。
这里是一个示例,创建大约 1MB 的 MP4 文件 (10kbit*1024*800/8 = 1MB):
ffmpeg -y -f lavfi -i testsrc=size=3840x2160:rate=1 -vf hue=s=0 -vcodec libx264 -tune zerolatency -b:v 10k -minrate 10k -maxrate 10k -t 800 -movflags +faststart -bufsize 1024k vid.mp4
生成 50MB 时长 5 秒的 MP4 文件:
5 秒的 50MB 大小需要大约 80,000,000 bis/sec 的比特率。
由于码率很高,我们需要使用高分辨率和高帧率的输入帧。
我们还需要确保视频帧没有被很好地压缩。
推荐使用随机输入图像,因为随机数据很难压缩。
以下 Python 代码构建 300 个分辨率为 1920x1080 的随机图像,并使用 FFmpeg 将图像序列编码为 MP4 视频文件:
import numpy as np
import cv2
import subprocess as sp
import os
# Build random input files (set of Tiff images).
# Use random data
# Use Full HD video frames at 60Hz
width, height, fps = 1920, 1080, 60
# Video duration in seconds
n_seconds = 5
for i in range (n_seconds*fps):
# Random gray image in resolution width by height.
img = np.random.randint(0, 255, (height, width), np.uint8)
# Images sequance file names (about 1GBytes of disk space):
# 00000.tif, 00001.tif, 00002.tif, 00003.tif... 00299.tif
cv2.imwrite(str(i).zfill(5)+'.tif', img)
# Destination file size is 50MBytes.
file_size_in_bytes = 50*1024*1024
# Desired bitrate is 83886080*0.90 bits/second
# Multiply by 0.9 - Leave 10% for the headers.
bitrate = int(round(file_size_in_bytes*8*0.9 / n_seconds))
# Encode video from the sequence of random images (use H.264 video codec).
# Set the video bitrate to 75497472.
# Set buffer size to 75497472*10 (not too tight) If we specify a smaller -bufsize, ffmpeg will more frequently check for the output bit rate and constrain it... https://trac.ffmpeg.org/wiki/Limiting%20the%20output%20bitrate
sp.run('ffmpeg -y -r {} -i %05d.tif -vcodec libx264 -tune zerolatency -b:v {} -minrate {} -maxrate {} -movflags +faststart -bufsize {} vid.mp4'.format(fps, bitrate, bitrate, bitrate, bitrate*10))
vid.mp4 的大小非常接近 50MB。
【讨论】:
如果您提供正确的比特率和持续时间,您可以接近 50 MB。对于 5 秒的持续时间和 ~50 MB 的文件大小:
ffmpeg -f lavfi -i color=size=1280x720:duration=5 -c:v libx264 -x264-params "nal-hrd=cbr" -b:v 81920k -minrate 81920k -maxrate 81920k -bufsize 81920k -movflags +faststart video.mp4
注意:bitrate = file size / duration,bitrate 相关选项以bits 为单位,会有一些小的复用开销。这不会是准确的。
如果 ~50MB 足够好,这就是您需要做的所有事情。
【讨论】:
duration 设置所需的持续时间并计算适当的比特率(比特率 = 文件大小/持续时间)以大致匹配所需的输出文件大小。如果您需要帮助获取比特率值,请搜索“比特率计算器”。