文档:https://github.com/bytedance/AlphaPlayer
AlphaPlayer是直播中台使用的一个视频动画特效SDK,可以通过制作Alpha通道分离的视频素材,再在客户端上通过OpenGL ES重新实现Alpha通道和RGB通道的混合,从而实现在端上播放带透明通道的视频。
作为技术生成脚本的过程梳理下:
官方给出的命令:
python convertAlphaVideo.py --dir 'your pictures parent file path'
2.用到官方给的Python脚本:convertAlphaVideo.py
官方给出的有些问题,修改了下才能跑通,已给官方提PR,脚本在下面分享给大家:convertAlphaVideo.py
3.需要一系列的序列帧,就是一套帧图片,然后将这些帧图片生成一个MP4文件
4.这一步简单,但是经常被忽略,就是修改所有图片的名字,对所有图片重命名为5个字符的名字,比如:00001.png 00002.png
5.运行脚本生成目标礼物视频MP4
个人GitHub: https://github.com/HuaDanJson QQ : 381266395
修改后的:convertAlphaVideo.py
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import os
import subprocess
import sys
import shutil
import argparse
isDebug = False
needZip = False
outputVideoPath = ""
imageDir = ""
srcPath = ""
maskPath = ""
outputPath = ""
oVideoFilePath = ""
fps = 15
bitrate = 3904
def main():
parser = argparse.ArgumentParser(description='manual to this script')
parser.add_argument('--file', type=str, default = None)
parser.add_argument('--dir', type=str, default = None)
parser.add_argument('--zip', type=str2bool, nargs='?', const=True, default = False, help="Activate zip mode.")
parser.add_argument('--fps', type=int, default = 15)
parser.add_argument('--bitrate', type=int, default = 3904)
args = parser.parse_args()
print("convertAlphaVideo.py running")
global needZip
needZip = args.zip
fps = args.fps
bitrate = args.bitrate
print "args.zip: ", args.zip
if not args.file is None:
parseVideoFile(args.file)
elif not args.dir is None:
parseImageDir(args.dir)
else:
print("params is None!")
return
print("finish")
def str2bool(v):
if isinstance(v, bool):
return v
if v.lower() in ('yes', 'true', 't', 'y', '1'):
return True
elif v.lower() in ('no', 'false', 'f', 'n', '0'):
return False
else:
raise argparse.ArgumentTypeError('Boolean value expected.')
def help():
print("help ~")
def parseVideoFile(path):
print(">>>>>>> paraseVideoFile, file is %s" % path)
parentDir = os.path.basename(path)
parentDir = parentDir.split('.')[0] + "/"
initDir(parentDir)
videoToImage(path, imageDir)
parseImageList(imageDir)
imagesToVideo(outputPath, oVideoFilePath)
shutil.rmtree(parentDir + "temp/")
print(">>>>>> convert alpha video finish, video file path is : %s" % oVideoFilePath)
def parseImageDir(path):
parentDir = os.path.abspath(path) + "/"
print(">>>>>>> paraseImageDir, dirName is %s" % parentDir)
initDir(parentDir)
parseImageList(parentDir)
imagesToVideo(outputPath, oVideoFilePath)
shutil.rmtree(parentDir + "temp/")
print(">>>>>> convert alpha video finish, video file path is : %s" % oVideoFilePath)
def initDir(parentDir):
global imageDir
imageDir = parentDir + "temp/imageDir/"
mkdir(imageDir)
global srcPath
srcPath = parentDir + "temp/source/"
mkdir(srcPath)
global maskPath
maskPath = parentDir + "temp/mask/"
mkdir(maskPath)
global outputPath
outputPath = parentDir + "temp/output/"
mkdir(outputPath)
global outputVideoPath
outputVideoPath = parentDir + "output/"
mkdir(outputVideoPath)
global oVideoFilePath
oVideoFilePath = outputVideoPath + "video.mp4"
def parseImageList(inputPath):
fileList = os.listdir(inputPath)
totalLength = len(fileList)
progress = 0
for fileName in fileList:
if os.path.splitext(fileName)[1] == ".png":
inputImageFile = inputPath + fileName
srcImageFile = srcPath + os.path.splitext(fileName)[0] + ".jpg"
tempMaskImageFile = maskPath + os.path.splitext(fileName)[0] + "_temp.jpg"
maskImageFile = maskPath + os.path.splitext(fileName)[0] + ".jpg"
outputImageFile = outputPath + os.path.splitext(fileName)[0] + ".jpg"
removeAlpha(inputImageFile, srcImageFile)
if needZip:
separateAlphaChannel(inputImageFile, tempMaskImageFile)
zipAlphaChannelPro(tempMaskImageFile, maskImageFile)
else:
separateAlphaChannel(inputImageFile, maskImageFile)
appendImageLand(srcImageFile, maskImageFile, outputImageFile)
deleteTempFile(srcImageFile)
deleteTempFile(maskImageFile)
deleteTempFile(tempMaskImageFile)
progress += 1
updateProgress(progress, totalLength)
def videoToImage(videoPath, imageDir):
command = "ffmpeg -i {} -r {} {}%05d.png".format(videoPath, fps, imageDir)
if isDebug:
print (command)
ret = subprocess.Popen(command, shell = True)
ret.communicate()
def removeAlpha(imageSrc, imageDst):
command = "convert {} -background black -alpha remove {}".format(imageSrc, imageDst)
if isDebug:
print (command)
ret = subprocess.Popen(command, shell = True)
ret.communicate()
def separateAlphaChannel(imageFileOne, imageFileTwo):
command = "convert {} -channel A -separate {}".format(imageFileOne, imageFileTwo)
if isDebug:
print (command)
ret = subprocess.Popen(command, shell = True)
ret.communicate()
def zipAlphaChannel(imageSrc, imageDst):
srcImage = cv2.imread(imageSrc)
shape = srcImage.shape
dstImage = np.zeros((int(shape[0]), int(shape[1])/3, int(shape[2])), np.uint8)
dstShape = dstImage.shape
height = dstShape[0]
width = dstShape[1]
channels = dstShape[2]
for row in range(height):
for col in range(width):
for channel in range(channels):
dstImage[row][col][channel] = srcImage[row][col * 3 + channel][0]
cv2.imwrite(imageDst, dstImage)
def zipAlphaChannelPro(imageSrc, imageDst):
srcImage = cv2.imread(imageSrc)
shape = srcImage.shape
dstImage = np.zeros((int(shape[0]), int(shape[1])/3, int(shape[2])), np.uint8)
dstShape = dstImage.shape
height = dstShape[0]
width = dstShape[1]
channels = dstShape[2]
for row in range(height):
for col in range(width):
for channel in range(channels):
dstImage[row][col][channel] = srcImage[row][col + channel * width][0]
cv2.imwrite(imageDst, dstImage)
def appendImageLand(imageFileOne, imageFileTwo, imageFileAppend):
command = "convert +append {} {} {}".format(imageFileTwo, imageFileOne, imageFileAppend)
if isDebug:
print (command)
ret = subprocess.Popen(command, shell = True)
ret.communicate()
def deleteTempFile(filePath):
if os.path.exists(filePath):
os.remove(filePath)
def imagesToVideo(imagesPath, videoFile):
command = "ffmpeg -r {} -i {}%05d.jpg -vcodec libx264 -pix_fmt yuv420p -b {}k {}".format(fps, imagesPath, bitrate, videoFile)
if isDebug:
print (command)
ret = subprocess.Popen(command, shell = True)
ret.communicate()
def updateProgress(progress, total):
percent = round(1.0 * progress / total * 100,2)
sys.stdout.write('\rprogress : %s [%d/%d]'%(str(percent)+'%', progress, total))
sys.stdout.flush()
def mkdir(path):
folder = os.path.exists(path)
if not folder:
os.makedirs(path)
if __name__ == '__main__':
main()