python压缩视频文件_python压缩图片和视频

本文介绍了如何使用Python对图片和视频进行压缩,通过创建一个类`Compress_Pic_or_Video`,利用PIL库处理图片压缩,使用ffmpeg处理视频压缩。压缩策略包括根据文件大小决定是否压缩,以及对图片的字节串使用zlib压缩,对视频调整帧率、编码器参数等。
摘要由CSDN通过智能技术生成

引言

在真实项目中,往往要进行图片的传输和视频的传输,但因为用户上传的图片和视频所占用的大小问题而导致占用服务器的空间多,并且用户访问这些图片的时候因为图片或视频太大而长时间加载,所以要对用户上传的视频和图片进行压缩,减少服务器的占用空间和加载时间。

1.新建一个类

我们先新建一个保存图片或视频的一个类

import platform

class Compress_Pic_or_Video(object):

def __init__(self,filePath,inputName,outName=""):

self.filePath = filePath #文件地址

self.inputName = inputName #输入的文件名字

self.outName = outName #输出的文件名字

self.system_ = platform.platform().split("-",1)[0]#判断是那个操作系统,因为我的服务器是Linux的但我电脑是windows的,所以只设置了这两个系统的判断

if self.system_ == "Windows":#对windows的文件格式进行设置

self.filePath = (self.filePath + "\\") if self.filePath.rsplit("\\",1)[-1] else self.filePath

elif self.system_ == "Linux":#对Linux的文件格式进行设置

self.filePath = (self.filePath + "/") if self.filePath.rsplit("/",1)[-1] else self.filePath

self.fileInputPath = self.filePath + inputName#拼接输入的路径

self.fileOutPath = self.filePath + outName#拼接输出的路径

2.设置判断文件是否是图片或视频

@property

def is_picture(self):

picSuffixSet = {"BMP","GIF","JPEG","TIFF","PNG","SVG","PCX","WMF","EMF","LIC","EPS","TGA","JPG"}#常用后缀,集合的搜索速度快,所以用集合而不用列表,还能做到去重,避免输入了重复的后缀名

suffix = self.fileInputPath.rsplit(".",1)[-1].upper()

if suffix in picSuffixSet:

return True

else:

return False

@property

def is_video(self):

videoSuffixSet = {"WMV","ASF","ASX","RM","RMVB","MP4","3GP","MOV","M4V","AVI","DAT","MKV","FIV","VOB"}

suffix = self.fileInputPath.rsplit(".",1)[-1].upper()

if suffix in videoSuffixSet:

return True

else:

return False

3.对上传的图片进行压缩

import zlib#压缩的库

import threading#多线程

from PIL import Image

def SavePic(self):

fpsize = os.path.getsize(self.fileInputPath) / 1024 # 获得图片多少K os.path.getsize(self.picPath)返回的是字节

if fpsize >= 50.0: # 是否大于50K

im = Image.open(self.fileInputPath) # 打开图片

imBytes = im.tobytes() # 把图片转换成bytes流

imBytes = zlib.compress(imBytes, 5) # 对图像字节串进行压缩,第二个参数是压缩率有-1,0-9,按个人情况进行设置,我都试过了感觉没多大变化,所以随便设置了5

im2 = Image.frombytes('RGB', im.size, zlib.decompress(imBytes)) # 压缩成新的图片

if self.outName:

im2.save(self.fileOutPath) #不覆盖原图

return (self.fileOutPath,os.path.getsize(self.fileOutPath))

else:

im2.save(self.fileInputPath) #覆盖原图

return (self.fileInputPath,os.path.getsize(self.fileInputPath))

else:

return True

def Compress_Picture(self):

#异步保存打开下面的代码,注释同步保存的代码,我选用的是异步保存,因为如果图片太大用同步的话会阻塞程序的运行,按自己的情况去选择,也可以设置一个变量,然后用判断来看是否启动多线程保存

thr = threading.Thread(target=self.SavePic)

thr.start()

#下面为同步保存

# fpsize = os.path.getsize(self.fileInputPath) / 1024 # 获得图片多少K os.path.getsize(self.picPath)返回的是字节

# if fpsize >= 50.0: # 是否大于50K

# im = Image.open(self.fileInputPath) # 打开图片

# imBytes = im.tobytes() # 把图片转换成bytes流

# imBytes = zlib.compress(imBytes, 5) # 对图像字节串进行压缩

# im2 = Image.frombytes('RGB', im.size, zlib.decompress(imBytes)) # 压缩成新的图片

# if self.outName:

# im2.save(self.fileOutPath) # 不覆盖原图

# return (self.fileOutPath, os.path.getsize(self.fileOutPath) / 1024)

# else:

# im2.save(self.fileInputPath) # 覆盖原图

# return (self.fileInputPath, os.path.getsize(self.fileInputPath) / 1024)

# else:

# return True

4.对上传的视频进行压缩

import os

def SaveVideo(self):

fpsize = os.path.getsize(self.fileInputPath) / 1024

if fpsize >= 150.0: #大于150KB的视频需要压缩

if self.outName:

compress = "ffmpeg -i {} -r 10 -pix_fmt yuv420p -vcodec libx264 -preset veryslow -profile:v baseline -crf 23 -acodec aac -b:a 32k -strict -5 {}".format(self.fileInputPath,self.fileOutPath)

isRun = os.system(compress)

else:

compress = "ffmpeg -i {} -r 10 -pix_fmt yuv420p -vcodec libx264 -preset veryslow -profile:v baseline -crf 23 -acodec aac -b:a 32k -strict -5 {}".format(self.fileInputPath, self.fileInputPath)

isRun = os.system(compress)

if isRun != 0:

return (isRun,"没有安装ffmpeg")

return True

else:

return True

def Compress_Video(self):

# 异步保存打开下面的代码,注释同步保存的代码

thr = threading.Thread(target=self.SaveVideo)

thr.start()

#下面为同步代码

# fpsize = os.path.getsize(self.fileInputPath) / 1024

# if fpsize >= 150.0: # 大于150KB的视频需要压缩

# compress = "ffmpeg -i {} -r 10 -pix_fmt yuv420p -vcodec libx264 -preset veryslow -profile:v baseline -crf 23 -acodec aac -b:a 32k -strict -5 {}".format(

# self.fileInputPath, self.fileOutPath)

# isRun = os.system(compress)

# if isRun != 0:

# return (isRun, "没有安装ffmpeg")

# return True

# else:

# return True

我这里使用了是ffmpeg对视频进行压缩,这个是一个非常好用的工具,Linux和windows都有,在Linux中可以使用apt install ffmpeg进行安装(我用的是Ubuntu的系统,所以使用apt进行安装,如果用的是Centos的用对应的yum进行安装就行了)

ffmpeg命令解释

ffmpeg -i 1.mp4 -r 10 -pix_fmt yuv420p -vcodec libx264 -preset veryslow -profile:v baseline -crf 23 -acodec aac -b:a 32k -strict -5 147fss.mp4

-i 输入的视频文件

-r 每一秒的帧数,一秒10帧大概就是人眼的速度

-pix_fmt 设置视频颜色空间 yuv420p网络传输用的颜色空间 ffmpeg -pix_fmts可以查看有哪些颜色空间选择

-vcodec 软件编码器,libx264通用稳定

-preset 编码机预设 编码机预设越高占用CPU越大 有十个参数可选 ultrafast superfast veryfast(录制视频选用) faster fast medium(默认) slow slower veryslow(压制视频时一般选用) pacebo

-profile:v 压缩比的配置 越往左边压缩的越厉害,体积越小 baseline(实时通信领域一般选用,画面损失越大) Extended Main(流媒体选用) High(超清视频) High 10 High 4:2:2 High 4:4:4(Predictive)

-level:v 对编码机的规范和限制针对不通的使用场景来操作,也就是不同分辨率设置不同的值(这个我没有设置,因为这个要根据不同的分辨率进行设置的,具体要去官方文档查看)

-crf 码率控制模式 用于对画面有要求,对文件大小无关紧要的场景 0-51都可以选择 0为无损 一般设置18 - 28之间 大于28画面损失严重

-acodec 设置音频编码器

完整代码

import sys

import os

import zlib

import threading

import platform

from PIL import Image

class Compress_Pic_or_Video(object):

def __init__(self,filePath,inputName,outName=""):

self.filePath = filePath #文件地址

self.inputName = inputName #输入的文件名字

self.outName = outName #输出的文件名字

self.system_ = platform.platform().split("-",1)[0]

if self.system_ == "Windows":

self.filePath = (self.filePath + "\\") if self.filePath.rsplit("\\",1)[-1] else self.filePath

elif self.system_ == "Linux":

self.filePath = (self.filePath + "/") if self.filePath.rsplit("/",1)[-1] else self.filePath

self.fileInputPath = self.filePath + inputName

self.fileOutPath = self.filePath + outName

@property

def is_picture(self):

picSuffixSet = {"BMP","GIF","JPEG","TIFF","PNG","SVG","PCX","WMF","EMF","LIC","EPS","TGA","JPG"}

suffix = self.fileInputPath.rsplit(".",1)[-1].upper()

if suffix in picSuffixSet:

return True

else:

return False

@property

def is_video(self):

videoSuffixSet = {"WMV","ASF","ASX","RM","RMVB","MP4","3GP","MOV","M4V","AVI","DAT","MKV","FIV","VOB"}

suffix = self.fileInputPath.rsplit(".",1)[-1].upper()

if suffix in videoSuffixSet:

return True

else:

return False

def SavePic(self):

fpsize = os.path.getsize(self.fileInputPath) / 1024 # 获得图片多少K os.path.getsize(self.picPath)返回的是字节

if fpsize >= 50.0: # 是否大于50K

im = Image.open(self.fileInputPath) # 打开图片

imBytes = im.tobytes() # 把图片转换成bytes流

imBytes = zlib.compress(imBytes, 5) # 对图像字节串进行压缩

im2 = Image.frombytes('RGB', im.size, zlib.decompress(imBytes)) # 压缩成新的图片

if self.outName:

im2.save(self.fileOutPath) #不覆盖原图

return (self.fileOutPath,os.path.getsize(self.fileOutPath))

else:

im2.save(self.fileInputPath) #覆盖原图

return (self.fileInputPath,os.path.getsize(self.fileInputPath))

else:

return True

def SaveVideo(self):

fpsize = os.path.getsize(self.fileInputPath) / 1024

if fpsize >= 150.0: #大于150KB的视频需要压缩

if self.outName:

compress = "ffmpeg -i {} -r 10 -pix_fmt yuv420p -vcodec libx264 -preset veryslow -profile:v baseline -crf 23 -acodec aac -b:a 32k -strict -5 {}".format(self.fileInputPath,self.fileOutPath)

isRun = os.system(compress)

else:

compress = "ffmpeg -i {} -r 10 -pix_fmt yuv420p -vcodec libx264 -preset veryslow -profile:v baseline -crf 23 -acodec aac -b:a 32k -strict -5 {}".format(self.fileInputPath, self.fileInputPath)

isRun = os.system(compress)

if isRun != 0:

return (isRun,"没有安装ffmpeg")

return True

else:

return True

def Compress_Picture(self):

#异步保存打开下面的代码,注释同步保存的代码

thr = threading.Thread(target=self.SavePic)

thr.start()

#下面为同步保存

# fpsize = os.path.getsize(self.fileInputPath) / 1024 # 获得图片多少K os.path.getsize(self.picPath)返回的是字节

# if fpsize >= 50.0: # 是否大于50K

# im = Image.open(self.fileInputPath) # 打开图片

# imBytes = im.tobytes() # 把图片转换成bytes流

# imBytes = zlib.compress(imBytes, 5) # 对图像字节串进行压缩

# im2 = Image.frombytes('RGB', im.size, zlib.decompress(imBytes)) # 压缩成新的图片

# if self.outName:

# im2.save(self.fileOutPath) # 不覆盖原图

# return (self.fileOutPath, os.path.getsize(self.fileOutPath) / 1024)

# else:

# im2.save(self.fileInputPath) # 覆盖原图

# return (self.fileInputPath, os.path.getsize(self.fileInputPath) / 1024)

# else:

# return True

def Compress_Video(self):

# 异步保存打开下面的代码,注释同步保存的代码

thr = threading.Thread(target=self.SaveVideo)

thr.start()

#下面为同步代码

# fpsize = os.path.getsize(self.fileInputPath) / 1024

# if fpsize >= 150.0: # 大于150KB的视频需要压缩

# compress = "ffmpeg -i {} -r 10 -pix_fmt yuv420p -vcodec libx264 -preset veryslow -profile:v baseline -crf 23 -acodec aac -b:a 32k -strict -5 {}".format(

# self.fileInputPath, self.fileOutPath)

# isRun = os.system(compress)

# if isRun != 0:

# return (isRun, "没有安装ffmpeg")

# return True

# else:

# return True

if __name__ == "__main__":

b = sys.argv[1:]#测试压缩

savepic = Compress_Pic_or_Video(b[0],b[1],b[2])

print(savepic.Compress_Picture())

测试情况

对图片进行压缩

左边为没压缩过的原图,右边是压缩过后的原图,两张图片像素都是一样的,两张图片用肉眼几乎分辨不出差别

对视频进行压缩

左边为未压缩过的原视频文件,右边为压缩过的视频文件,可见帧宽度与帧高度都没发生过改变,只是修改了数据速率,总比特率等的这些信息,源文件帧速率为每秒12帧,现在压缩成了每秒10帧,人眼是没办法分别出12帧与10帧的区别的,我测试过原视频和压缩后的视频观看上是没有却别的,声轨也听不出。

参考的文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值