#Python应用#--MoviePy之批量视频处理工具

user

雨橙

中国.四川.成都

世界之上、唯有远见、惟爱不变。


最近因客户要求。需要制作一个批量转换视频的工具。
要求是对视频进行一系列的剪辑操作并转换成.MOV格式的视频。

平时我们用软件AE,PR都可以做这样的事情。
但是如果需要批量处理那么就需要自动化软件来运行比较方便。
下面是我写的这个软件的代码。(没有很好的封装 ^_^,大家将就看一下。)
有三个模块文件:分别是:DBD.py ,  MainFrame.py , movieform.py
贴上源代码:

DBD.py (数据库访问模块,主要实现对数据库用户的访问及更新操作)
#! /usr/bin/python
# _*_ coding:utf-8 _*_

import MySQLdb
import base64

linestr = "DS47lLinx=\nx|MjEIuM7TA1\n|bZG9XZ\n|ZG94\n|bWweQ==\n"
liststr = linestr.split("|")
db = MySQLdb.connect(base64.decodestring(liststr[1]), base64.decodestring(liststr[2]), base64.decodestring(liststr[3]), base64.decodestring(liststr[4]))
db.set_character_set('utf8')
cursor = db.cursor()

def insertJqm(sql):
    try:
       cursor.execute(sql)
       db.commit()
    except:
       db.rollback()

def selectBysql_one(sql):
    cursor.execute(sql)
    info = cursor.fetchone()
    return info


def selectBysql(sql):
    cursor.execute(sql)
    info = cursor.fetchone()
    if info:
        return True
    else:
        return False


def selectBysqlALL(sql):
    cursor.execute(sql)
    info = cursor.fetchall()
    return info


MainFrame.py(GUI登陆入口界面,这里使用wxPython来实现GUI)
#! /usr/bin/python
# _*_ coding:utf-8 _*_

import six
import wx
import DBD
# import http.client
import httplib
import time
import datetime
import hashlib
import movieform
import socket
import uuid
from json import load
from urllib2 import urlopen

class ButtonFrame(wx.Frame):
    def __init__(self):
        mm=wx.DisplaySize()
        wx.Frame.__init__(self, None, -1, u'视频批处理工具',
            size=(290, 200),pos=((mm[0]-290)/2,(mm[1]-200)/2),style=wx.DEFAULT_DIALOG_STYLE)
        panel = wx.Panel(self, -1)
        self.icon = wx.Icon('favicon.ico', wx.BITMAP_TYPE_ICO)
        self.SetIcon(self.icon)
        self.isMax = False
        self.Maximize(False)

        wx.StaticText(panel, -1, u"用户名:", pos = (35, 32))
        self.uname = wx.TextCtrl(panel, -1, "", pos = (90, 30),size=(150,25))

        wx.StaticText(panel, -1, u"密   码:", pos = (35, 75))
        self.upws = wx.TextCtrl(panel, -1, "", pos = (90, 72),size=(150,25),style=wx.TE_PASSWORD)

        self.buttonLogin = wx.Button(panel, -1, u"登  陆", pos=(90, 115),size=(65,30))
        self.Bind(wx.EVT_BUTTON, self.OnclickLogin, self.buttonLogin)
        self.buttonLogin.SetDefault()


        self.buttonReset = wx.Button(panel, -1, u"重  填", pos=(175, 115),size=(65,30))
        self.Bind(wx.EVT_BUTTON, self.OnclickReset, self.buttonReset)
        #self.buttonReset.SetDefault()

    def getdatetime(self,host):
        conn = httplib.HTTPConnection(host)
        conn.request("GET", "/")
        r = conn.getresponse()
        ts = r.getheader('date')
        #将GMT时间转换成北京时间
        ltime= time.strptime(ts[5:25], "%d %b %Y %H:%M:%S")
        ttime=time.localtime(time.mktime(ltime)+8*60*60)
        dat="%u-%02u-%02u"%(ttime.tm_year,ttime.tm_mon,ttime.tm_mday)
        tm="%02u:%02u:%02u"%(ttime.tm_hour,ttime.tm_min,ttime.tm_sec)
        return datetime.datetime.strptime(dat+' '+tm, '%Y-%m-%d %H:%M:%S')

    def getipmacname(self):
        def get_mac_address():
            mac=uuid.UUID(int = uuid.getnode()).hex[-12:]
            return ":".join([mac[e:e+2] for e in range(0,11,2)])

        myname = socket.getfqdn(socket.gethostname())
        mymacaddr = get_mac_address()
        #myip = load(urlopen('http://jsonip.com'))['ip']

        h2 = hashlib.md5()
        #h2.update(myname+mymacaddr+myip)
        h2.update(myname+mymacaddr)
        return h2.hexdigest()

    def OnclickLogin(self,event):
        u_name = self.uname.GetValue()
        u_pws = self.upws.GetValue()

        if u_name == "":
            dlg1 = wx.MessageDialog(None, u"请填写用户名!", u"温馨提示", wx.OK)
            if dlg1.ShowModal() == wx.ID_OK:
                dlg1.Destroy()
                return

        if u_pws == "":
            dlg2 = wx.MessageDialog(None, u"请填写密码!", u"温馨提示", wx.OK)
            if dlg2.ShowModal() == wx.ID_OK:
                dlg2.Destroy()
                return

        hl = hashlib.md5()
        hl.update(u_pws)
        u_pws = hl.hexdigest()
        sql = "selects userid,username,userpws,user_jqm,usercnt,userregtime,userendtime from usertab where username='"+u_name+"' and userpws='"+u_pws+"'"
        flag = DBD.selectBysql(sql)
        if not flag:
            dlg = wx.MessageDialog(None, u"用户名或密码不正确,请重新填写.", u"温馨提示", wx.OK | wx.ICON_ERROR )
            if dlg.ShowModal() == wx.ID_OK:
                #self.OnclickReset(event)
                pass
            dlg.Destroy()
        else:
            info = DBD.selectBysql_one(sql)
            userid = info[0]
            username = info[1]
            userpws = info[2]
            user_jqm = info[3]
            usercnt = info[4]
            userregtime = info[5]
            userendtime = info[6]

            currentdatetime = self.getdatetime("www.baidu.com")
            if(currentdatetime > userendtime):
                dlg = wx.MessageDialog(None, u"软件授权已过期!请联系管理员重新获取授权!", u"温馨提示", wx.OK | wx.ICON_ERROR )
                if dlg.ShowModal() == wx.ID_OK:
                    pass
                dlg.Destroy()
            else:
                ipmacname = self.getipmacname()
                nowdatetime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                if not user_jqm:
                    sql = "UPDATEs usertab SET user_jqm='"+ipmacname+"' where username='"+u_name+"' and userpws='"+u_pws+"'"
                    DBD.insertJqm(sql)

                    sql1 = "UPDATEs usertab SET user_logintime='"+nowdatetime+"' where username='"+u_name+"' and userpws='"+u_pws+"'"
                    DBD.insertJqm(sql1)

                    mbf = movieform.ButtonFrame(userid,username,userpws,ipmacname,usercnt,userregtime,userendtime)
                    mbf.Show()


                    DBD.db.close()
                    self.Close()
                    self.Destroy()
                else:
                    if ipmacname == user_jqm:
                        sql1 = "UPDATEs usertab SET user_logintime='"+nowdatetime+"' where username='"+u_name+"' and userpws='"+u_pws+"'"
                        DBD.insertJqm(sql1)

                        mbf = movieform.ButtonFrame(userid,username,userpws,user_jqm,usercnt,userregtime,userendtime)
                        mbf.Show()
                        DBD.db.close()
                        self.Close()
                        self.Destroy()
                    else:
                        dlg = wx.MessageDialog(None, u"暂未授权!请联系管理员获取授权!", u"温馨提示", wx.OK | wx.ICON_ERROR )
                        if dlg.ShowModal() == wx.ID_OK:
                            #self.OnclickReset(event)
                            pass
                        dlg.Destroy()



    def OnclickReset(self,event):
        self.uname.SetValue("")
        self.upws.SetValue("")
        pass

if __name__ == '__main__':
    app = wx.App()
    frame = ButtonFrame()
    frame.SetSize((290,200))
    frame.Show(True)
    app.MainLoop()


movieform.py(这个模块主要完成视频的批处理操作)
#! /usr/bin/python
# _*_ coding:utf-8 _*_

#import http.client
import httplib
import time
import datetime
import socket
import uuid
import hashlib
from json import load
from urllib2 import urlopen
import os
import wx

# import imageio
# imageio.plugins.ffmpeg.download()

import moviepy
from moviepy.editor import *

# from moviepy.config import change_settings
# 32位
# change_settings({"IMAGEMAGICK_BINARY": r"ffmpeg\convert.exe"})

# 64位
# change_settings({"IMAGEMAGICK_BINARY": r"ffmpeg\convert_64.exe"})


class ButtonFrame(wx.Frame):
    def __init__(self,userid,username,userpws,user_jqm,usercnt,userregtime,userendtime):

        self.userid = userid
        self.username = username
        self.userpws = userpws
        self.user_jqm = user_jqm
        self.usercnt = usercnt
        self.userregtime = userregtime
        self.userendtime = userendtime


        mm=wx.DisplaySize()
        title_str = u"批量视频工具|截止时间:"+str(self.userendtime)
        wx.Frame.__init__(self, None, -1, title_str,
            size=(350, 224),pos=((mm[0]-350)/2,(mm[1]-200)/2),style=wx.DEFAULT_DIALOG_STYLE)
        panel = wx.Panel(self, -1)
        self.isMax = False
        self.Maximize(False)

        self.icon = wx.Icon('favicon.ico', wx.BITMAP_TYPE_ICO)
        self.SetIcon(self.icon)

        # self.icon = wx.EmptyIcon()
        # self.icon.CopyFromBitmap(wx.BitmapFromImage(wx.Image(("favicon.ico"), wx.BITMAP_TYPE_ICO)))
        # self.SetIcon(self.icon)

        wx.StaticText(panel, -1, u"源目录:", pos = (10, 32))
        self.sourceurl = wx.TextCtrl(panel, -1, "", pos = (65, 30),size=(200,25))
        self.buttonsource = wx.Button(panel, -1, u"选择目录", pos=(275, 30),size=(60,25))
        self.Bind(wx.EVT_BUTTON, self.OnclickSource, self.buttonsource)
        self.buttonsource.SetDefault()


        wx.StaticText(panel, -1, u"目标目录:", pos = (10, 80))
        self.targeturl = wx.TextCtrl(panel, -1, "", pos = (65, 75),size=(200,25))
        self.buttontarget = wx.Button(panel, -1, u"选择目录", pos=(275, 75),size=(60,25))
        self.Bind(wx.EVT_BUTTON, self.OnclickTarget, self.buttontarget)
        self.buttontarget.SetDefault()

        self.buttonLogin = wx.Button(panel, -1, u"开始任务", pos=(90, 125),size=(165,30))
        self.Bind(wx.EVT_BUTTON, self.OnclickLogin, self.buttonLogin)
        self.buttonLogin.SetDefault()

        bottomtitle_str = u"欢迎使用!版权解释权归小牛软件所有!"
        if self.usercnt:
            bottomtitle_str = bottomtitle_str+u"[请获取正式版授权]"
        self.txt_tips = wx.TextCtrl(panel, -1, bottomtitle_str, pos = (0, 170),size=(344,25),style=wx.TE_READONLY | wx.TE_CENTER)

    def getdatetime(self,host):
        conn = httplib.HTTPConnection(host)
        conn.request("GET", "/")
        r = conn.getresponse()
        ts = r.getheader('date')
        #将GMT时间转换成北京时间
        ltime = time.strptime(ts[5:25], "%d %b %Y %H:%M:%S")
        ttime = time.localtime(time.mktime(ltime)+8*60*60)
        dat="%u-%02u-%02u"%(ttime.tm_year,ttime.tm_mon,ttime.tm_mday)
        tm="%02u:%02u:%02u"%(ttime.tm_hour,ttime.tm_min,ttime.tm_sec)
        return datetime.datetime.strptime(dat+' '+tm, '%Y-%m-%d %H:%M:%S')

    def getipmacname(self):
        def get_mac_address():
            mac = uuid.UUID(int = uuid.getnode()).hex[-12:]
            return ":".join([mac[e:e+2] for e in range(0,11,2)])

        myname = socket.getfqdn(socket.gethostname())
        mymacaddr = get_mac_address()
        #myip = load(urlopen('http://jsonip.com'))['ip']

        h2 = hashlib.md5()
        #h2.update(myname+mymacaddr+myip)
        h2.update(myname+mymacaddr)
        return h2.hexdigest()

    def OnclickLogin(self,event):
        u_sourceurl = self.sourceurl.GetValue()
        u_targeturl = self.targeturl.GetValue()

        if u_sourceurl == "":
            dlg1 = wx.MessageDialog(None, u"请选择视频源目录!", u"温馨提示", wx.OK)
            if dlg1.ShowModal() == wx.ID_OK:
                dlg1.Destroy()
                return

        if u_targeturl == "":
            dlg1 = wx.MessageDialog(None, u"请选择视频目标目录!", u"温馨提示", wx.OK)
            if dlg1.ShowModal() == wx.ID_OK:
                dlg1.Destroy()
                return

        self.txt_tips.SetValue(u"视频正在处理中.....请稍等......")
        time.sleep(2)

        currentdatetime = self.getdatetime("www.baidu.com")
        if(currentdatetime > self.userendtime):
            dlg = wx.MessageDialog(None, u"软件授权已过期!请联系管理员重新获取授权!", u"温馨提示", wx.OK | wx.ICON_ERROR )
            if dlg.ShowModal() == wx.ID_OK:
                pass
            dlg.Destroy()
            self.Close()
            self.Destroy()
        else:

            if self.getipmacname() != self.user_jqm:
                print("xxxx")
                dlg = wx.MessageDialog(None, u"暂未授权!请联系管理员获取授权!", u"温馨提示", wx.OK | wx.ICON_ERROR )
                if dlg.ShowModal() == wx.ID_OK:
                    pass
                dlg.Destroy()
                self.Close()
                self.Destroy()
            else:
                self.clip = Clips()
                self.clip.processclip(u_sourceurl,u_targeturl,self.txt_tips,self.usercnt)




    def OnclickSource(self,event):
        dlg1 = wx.DirDialog(None, u"选择视频源文件夹!", u"温馨提示", wx.OK)
        if dlg1.ShowModal() == wx.ID_OK:
            sourceurl_ = dlg1.GetPath()
            self.sourceurl.SetValue(sourceurl_)
            dlg1.Destroy()
            return

    def OnclickTarget(self,event):
        dlg1 = wx.DirDialog(None, u"选择视频目标文件夹!", u"温馨提示", wx.OK)
        if dlg1.ShowModal() == wx.ID_OK:
            targeturl_ = dlg1.GetPath()
            self.targeturl.SetValue(targeturl_)
            dlg1.Destroy()
            return

class Clips(object):
    def __init__(self):
        pass

    def processclip(self,source,target,txt_obj,usercnt):
        num = 0
        for root,dirs,files in os.walk(source):
            for file in files:
                clip = VideoFileClip(source+"\\"+file)
                if clip.duration>=2:
                    w,h = clip.size
                    clip = clip.subclip(0.5, clip.duration-0.5)
                    clip = moviepy.video.fx.all.mirror_x(clip)
                    clip = moviepy.video.fx.all.supersample(clip,2,5)

                    clip2 = VideoFileClip(source+"\\"+file)
                    clip2 = clip2.subclip(0.5, clip2.duration-0.5)
                    clip2 = moviepy.video.fx.all.mirror_x(clip2)
                    clip2 = clip2.resize((w-120, h-120))
                    clip2 = moviepy.video.fx.all.margin(clip2,left=60, right=60,top=60, bottom=60, color=(0, 0, 0), opacity=0)

                    clip_target = CompositeVideoClip([clip, clip2],bg_color=0,use_bgclip=True)
                    clip_target.write_videofile(target+"\\"+file,fps=25, codec=None,audio=False,rewrite_audio=False)

                    newfilename = file.split('.')
                    os.rename(os.path.join(target,file),os.path.join(target,newfilename[0]+".MOV"))

                    num += 1
                    txt_obj.SetValue(u"视频总个数:"+str(len(files))+u"个, 已成功完成 "+str(num)+u" 个")

                    if usercnt:
                        if num >= int(usercnt):
                            break


效果图如下:









总结:
这个批处理软件主要使用了MoviePy模块。结合了数据库。获取用户计算机名及MAC地址生成机器码,来进行授权访问。
代码很多地方处理的不太好。还需要优化一下。代码贴出来了。仅供大家参考学习。

有需要源码和软件的朋友可以找我。
我的邮箱: robinn#163.com (把#改为@)
posted at