Skip to content

Instantly share code, notes, and snippets.

@el-hult
Created August 20, 2021 12:20
Show Gist options
  • Save el-hult/390941d223d100832800bfbef36bb0e5 to your computer and use it in GitHub Desktop.
Save el-hult/390941d223d100832800bfbef36bb0e5 to your computer and use it in GitHub Desktop.
This code generates a very short video in the format of Yuv4mpeg2. It should be easily exendible to accept a series om bitmap images and create a video out of them.
WIDTH = 100
HEIGHT = 100
DURATION = 1 # seconds
FRAMES = 25*DURATION
def rgb2ycrcb(r,g,b):
""" ITU-R BT.601 (formerly CCIR 601) transformation
input in range 0-255
output in range 16-235 (headroom/footroom) for Y'
output in range 16-240 (headroom/footroom) for Cr/Cb
The man pages describes one shold use CCIR-601 colorspace for yuv4mpeg2 https://linux.die.net/man/5/yuv4mpeg
The transformation from 8-bit rgb to that space is described at wikipedia under https://en.wikipedia.org/wiki/YCbCr
"""
y = int( 16 + 65.841*r/255 + 128.553*g/255 + 24.966*b/255)
cb = int(128 - 37.797*r/255 - 74.203*g/255 + 112.000*b/255)
cr = int(128 + 112.000*r/255 - 93.786*g/255 - 18.214*b/255)
return y, cr, cb
with open("test.y4m", 'wb') as f:
# the simples possible header. more or less...
# See the man-pages https://linux.die.net/man/5/yuv4mpeg for an explanation
f.write(f"YUV4MPEG2 W{WIDTH} H{HEIGHT} F25:1 Ip A1:1 C444\n".encode())
for frame in range(FRAMES):
# each frame begins with a header. this is the simplest one
f.write(b'FRAME\n')
# construct image data pixel-per-pixel
# ... but reorganize it so it comes channel-wise
# in this setting each channel is called a 'plane'
# one may use subsampling, so one only keeps every 2nd or every 4th Cr and Cb value
# but in this example, I use C444, so we have the same number or chroma (Cr/Cb) values as luminosities (Y)
yplane = []
crplane = []
cbplane = []
for row in range(HEIGHT):
for col in range(WIDTH):
r,g,b = int(255*frame/FRAMES),int(row*255/HEIGHT),int(255*col/WIDTH)
y,cr,cb = rgb2ycrcb(r,g,b)
yplane.append(y)
crplane.append(cr)
cbplane.append(cb)
# finally write the planes.
# first the Y' plane
f.write(bytes(yplane))
# then the chroma-planes
# if not using the C444 options, the Cr and Cb planes could be shorter
f.write(bytes(crplane))
f.write(bytes(cbplane))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment