2

I want to generate a blank (black, white, content doesnt matter) MP4 video of a specific size, say 50 MB. How do I do this in python or using any other tool?

I have searched around but have only gotten code snippets to generate videos of specific dimensions.

FlyingAura
  • 1,541
  • 5
  • 26
  • 41

2 Answers2

2

You may create a shorter file and add zero padding to the end of the file.

The key is to place the "moov atom" at the begging of the file.

  • Generate synthetic (gray) video using 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
    

    You may use Python subprocess module:

    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')
    
  • Pad file with zeros at the end to make file size exactly 50 MB.

Here is the Python code:

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()

In case you want file size to be approximately 50MB, you may set the bitrate and the time.
The size in bits is going to be bitrate*time.
See How to force Constant Bit Rate using FFMPEG

Note: there is a small issue with the test pattern - it is too "compressible", so we need to set a very small bit rate.

Here is an example, creating approximately 1MB MP4 file (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

Update:

Generating 50MB MP4 file with 5 seconds duration:

Size of 50MB for 5 seconds requires bitrate of about 80,000,000 bis/sec.
Since the bitrate is very high, we need to use input frame with high resolution and high frame rate.
We also need to make sure that video frames are not well compressed.
Random input images are recommended, because random data is hardly compressible.

The following Python code builds 300 random images in resolution 1920x1080, and encode the images sequence to MP4 video file using FFmpeg:

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))

The size of vid.mp4 is very close to 50MB.

Rotem
  • 30,366
  • 4
  • 32
  • 65
  • How would I enforce a duration? Say I need a 50 MB file of 5 second duration? I tried adding the duration tag but that didnt do it. – user248884 Apr 07 '20 at 06:50
  • 50MB for 5 seconds is too large. 50MB for 50 seconds maybe possible. The encoder uses the selected bitrate as an upper bound. You need to encode random content that is not well compressed. The zero padding sould also work. Can you tell what do you need it for? Why mp4? Why 50MB? – Rotem Apr 07 '20 at 12:32
  • @Rotem: I've created a video server that can only serve 5s, 10s & 15s videos. The max size that the 5s video could be is 50 MB. Mp4 because the custom-built media player is only allowed to play mp4 video format. This is all in the project requirement. I'm ok encoding random content that is not well compressed. How do we do it? – FlyingAura Apr 07 '20 at 12:56
  • Are there any restrictions about the video CODEC? frame rate? resolution? – Rotem Apr 07 '20 at 14:03
  • I update my post - create 50MB MP4 file with 5 seconds duration. – Rotem Apr 07 '20 at 15:11
0

You can come close to 50 MB if you provide the correct bitrate and duration. For a 5 second duration and ~50 MB file size:

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

Note: bitrate = file size / duration, bitrate related options are in bits, and there will be some minor muxing overhead. It won't be exact.

If ~50MB is good enough that's all you need to do.

llogan
  • 121,796
  • 28
  • 232
  • 243
  • The dd step will result in corrupted packets. – Gyan Apr 07 '20 at 06:11
  • @llogan: How would I enforce a duration? Say I need a 50 MB file of 5 second duration? By your formula, I tweaked the file size (dimensions) but that didnt really do it. – user248884 Apr 07 '20 at 06:54
  • @Gyan I assumed so but it worked fine with a few lazy tests. – llogan Apr 07 '20 at 17:25
  • @user248884 See new example. Set desired duration with `duration` and calculate appropriate bitrate (bitrate = file size / duration) to approximately match desired output file size. Search for "bitrate calculator" if you need help getting bitrate values. – llogan Apr 07 '20 at 17:34