天天看點

Python 帶你進行短視訊二次創作

1目 标 場 景

無論是抖音還是快手等視訊平台,一旦一個視訊火了後,很多 UP 主都會争先搶後去模仿拍攝或剪輯,然後上傳到平台,最後都能帶來不錯的流量。

對于一般的短視訊,完全可以通過裁剪、特效轉場、加入混合圖層和字幕等一系列操作,很快就能制作出一個全新的視訊,這些操作完全可以使用 Python 來實作。

Python 帶你進行短視訊二次創作

本篇文章的目的是帶大家利用 Python 實作短視訊的二次創作。

2編 寫 代 碼

要實作短視訊的二次創作,一般需要下面 7 個步驟,分别是:擷取原始視訊屬性資料、視訊幀處理、視訊區域裁剪、制作背景圖檔視訊、合成多段視訊、生成描述字幕、加入字幕和背景音樂。

第 1 步,擷取原始視訊屬性資料

首先,利用 爬蟲 擷取無水印的原始視訊,Github 上有很多現成的輪子。

然後,執行個體化視訊片段 VideoFileClip,得到視訊的寬、高、幀率等基本屬性。

self.video_raw_clip = VideoFileClip(self.video_raw_path)

# 視訊寬、高
self.video_width, self.video_height = self.video_raw_clip.w, self.video_raw_clip.h

self.fps = self.video_raw_clip.fps      

接着,分離出音頻檔案,對原始視訊進行一次剪輯,去除掉視訊平台追加的公共畫面片段,重新生成一個視訊檔案。比如抖音預設會追加 4s 的公共視訊片段。

# 分離出音頻
self.audio = self.video_raw_clip.audio.subclip(0, self.video_raw_clip.duration - 4)

# 裁剪尾部的視訊素材
temp_video_clip = self.video_raw_clip.subclip(0, self.video_raw_clip.duration - 4)

# 生成新的視訊,并儲存到本地
temp_video_clip.set_audio(self.audio)

video_path = './source/temp_source_video.mp4'

temp_video_clip.write_videofile(video_path, codec='libx264',
                                        audio_codec='aac',
                                        temp_audiofile='temp-audio.m4a',
                                        remove_temp=True)      

第 2 步,視訊幀處理

要對一個視訊進行畫面裁剪,首先知道開始裁剪的 起始坐标點、裁剪的範圍。

Python 帶你進行短視訊二次創作

使用 ffmpeg 指令拿到視訊某一個時間點的圖檔幀,并儲存圖檔檔案到本地。

def time_to_hms(seconds_time):
    """
    時間轉為時分秒
    :param seconds_time: 秒數
    :return:
    """
    m, s = divmod(seconds_time, 60)
    h, m = divmod(m, 60)
    return "%02d:%02d:%02d" % (h, m, s)

def get_frame_from_video(video_name, frame_time, img_path):
    """
    擷取視訊某個時間的幀圖檔,儲存在本地
    get_frame_from_video('./../source/source.mp4', 1, './22.jpg')
    :param video_name: 視訊路徑
    :param frame_time: 截取幀的時間位置(s)
    :param img_path:生成圖檔的完整路徑
    :return:
    """
    # 秒轉為時、分、秒
    time_pre = time_to_hms(frame_time)

    os.system('ffmpeg -ss %s -i %s -frames:v 1 %s' % (time_pre, video_name, img_path))      

接着利用 PS 的标尺和選區工具配合資訊對話框,擷取要裁剪的起始坐标、裁剪寬高資料。

# 裁剪起始坐标
position1 = (0, 328)

# 630 為要裁剪的高度
position2 = (self.video_width, 630)      

第 3 步,視訊區域裁剪

moviepy 提供的 crop() 方法可以很友善的區域裁剪視訊。

需要注意的是,crop() 方法傳入的坐标值必須是 偶數,否則會導緻區域裁剪失敗。

def video_crop(self, position1, position2, croped_video_path):
     """
     視訊裁剪
     :return:
     """

     # 裁剪的坐标,包含左上角x軸和y軸;右下角x軸和y軸
     clip2 = fx.all.crop(self.video_clip, x1=position1[0], y1=position1[1], x2=position2[0], y2=position2[1])

     # 儲存檔案
     clip2.write_videofile(croped_video_path)

     # 時長
     self.time = clip2.duration

     return      

第 4 步,制作背景圖檔視訊

為了保證手機上的觀感,針對上面裁剪橫向視訊,需要混合加入一個豎屏的背景圖檔圖層或視訊。

之前寫過一篇 利用圖檔制作 GIF 視訊 的教程,這裡實作方式類似,即一個 圖檔幀循環寫入 到視訊檔案中。

def one_pic_to_video(image_path, output_video_path, fps, time):
    """
    一張圖檔合成視訊
    one_pic_to_video('./../source/1.jpeg', './../source/output.mp4', 25, 10)
    :param path: 圖檔檔案路徑
    :param output_video_path:合成視訊的路徑
    :param fps:幀率
    :param time:時長
    :return:
    """

    image_clip = ImageClip(image_path)
    img_width, img_height = image_clip.w, image_clip.h

    # 總共的幀數
    frame_num = (int)(fps * time)

    img_size = (int(img_width), int(img_height))

    fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')

    video = cv2.VideoWriter(output_video_path, fourcc, fps, img_size)

    for index in range(frame_num):
        frame = cv2.imread(image_path)
        # 直接縮放到指定大小
        frame_suitable = cv2.resize(frame, (img_size[0], img_size[1]), interpolation=cv2.INTER_CUBIC)

        # 把圖檔寫進視訊
        # 重複寫入多少次
        video.write(frame_suitable)

    # 釋放資源
    video.release()

    return VideoFileClip(output_video_path)      

需要注意的是,合成圖檔視訊的 幀率、時長 要和上一段視訊保持一緻。

第 5 步,合成兩段視訊

上面 2 步完成了原始視訊的區域裁剪和背景視訊的制作,現在可以将這兩段視訊進行一次合成。

由于兩段視訊的寬度很有可能不一樣,為了保證合成視訊的統一性,需要對其中一段視訊的長寬進行 等比例縮放,使得兩段視訊的寬度保證一緻。

def synthetic_video(video1_clip, video2_clip2):
    """
    合成兩段視訊,生成視訊的寬高以第一段視訊為準
    :param video1_clip:
    :param video2_clip2:
    :return:
    """
    # 最後生成視訊的寬、高
    width, height = video1_clip.w, video1_clip.h

    # 第二段視訊的實際寬、高
    video_width, video_height = video2_clip2.w, video2_clip2.h

    # 最第二段視訊進行縮放
    video_clip1 = video2_clip2.resize((width, width * video_height / video_width))

    # 合成視訊的路徑
    synthetic_video_clip = CompositeVideoClip([video1_clip, video_clip1.set_pos("center")])

    synthetic_video_clip.write_videofile(
        './source/temp_synthetic_video.mp4')

    return      

第 6 步,生成描述字幕

使用 TextClip 可以生成一個描述資訊,文字資訊屬性包含字型名稱、大小、顔色、位置、開始時間及持續時間都可以一起設定進去。

# 描述字幕
TextClip(text_content, font='./fonts/STHeiti Medium.ttc',
                    fontsize=font_params.get('size'), kerning=font_params.get('kerning'),
                    color=font_params.get('color')).set_position(("center", 150)).set_duration(duration)      

預設字型可能會導緻中文字幕不顯示,是以,最好指定特定的中文字型。

第 7 步,加入字幕和背景音樂

使用 CompositeVideoClip 即可以将字幕片段嵌入到視訊片段中,然後利用 set_audio 把音頻檔案為視訊增加一條音頻軌道。

最後寫入到檔案中,即可以生成一個新的短視訊。

# 加入字幕
video_with_text_clip = CompositeVideoClip([synthetic_video_clip, desc_text_clip.set_start(0)])

# 設定背景音樂
video_with_text_clip.set_audio(self.audio).write_videofile("output.mp4",
                                                                   codec='libx264',
                                                                   audio_codec='aac',
                                                                   temp_audiofile='temp-audio.m4a',
                                                                   remove_temp=True
                                                                   )
# 删除所有的臨時檔案
del_temp_file("./source/")      

3結 果 結 論