论农场视频节目的自动化处理

作者:康州盘古农场-Lioulun
审核:康州盘古农场-文韵

近日农场的战友为了便于爆料革命真相的快速传播不仅整理制作了精简的图像形式的每日重磅资讯,而且还将其发展成视频内容进一步扩大传播途径。为了减轻战友的工作量,笔者这里提出了一个自动化的视频节目处理方案。

一、分析问题

具体要求:通过计算机程式将每日重磅资讯的文本内容处理为视频形式的数字资料,视频必须具备字幕以及音频朗读等其它元素。

每日重磅的文本内容形式如下【其中每一行为一条独立的讯息】:


据称伊朗军事核计划负责人莫森·法赫扎德周五在德黑兰附近被暗杀

巴西总统博尔索纳罗儿子、国会众议员爱德华多指控华为5G技术涉间谍活动,中共严正交涉恐掀外交危机

国际专家团将进入武汉调查病毒起源  中共开始新一轮甩锅

林郑承认受美制裁无银行服务 改现金出行 家中现金成堆

台湾中油乍得矿区股权背后发现中共白手套叶简明背景,台当局要求彻查

中共报复加码,澳大利亚葡萄酒被加征巨额保证金

针对中共对澳洲产品采取的贸易制裁,澳前总理回应:铁腕对待澳洲只会损害北京的国际地位

韩情报机关:金正恩封锁平壤 处决至少两人

宾州立法机构将发起决议案,启动对宾州大选结果的争议

亚利桑那州立法机构将于11月30日就选举廉洁问题举行听证会,市长朱利安尼将代表川普总统出席

香港卫生署卫生防护中心周五报告说,新增感染病例92例,其中3例来自境外,89例属本地感染


这里,我们最为关注的问题核心是:1. 文本数据到视觉视频的生成;2. 文本数据到音频内容的生成;3. 内容要素的整合。

二、核心问题的解决方案

1. 文本数据到视觉视频的生成

关于文本数据到视频的生成,我们可以使用 ffmpeg 相关的软件套件或者开发库实现字幕的自动生成。具体操作可以这样:首先,我们人工编辑或者下载一段开场视频和一段播放正文时的背景视频;然后,我们编写程序将每一条资讯作为一个字幕压制到视频的指定时间和位置。

2. 文本数据到音频内容的生成

关于文本生成音频,目前看来最合适的方法还是使用在线的 TTS API ,不需要克服太多的技术障碍就能实现文本转换语音。

3. 内容要素的整合

如果是几乎不会变更的静态素材,例如:图标、节目名称等信息可以人工将其合成在背景视频中;如果是时常变化的信息,例如:时间、投稿人名称等可以交由程序进行动态合成。

三、技术实践

1. 实验环境

操作系统:GNU/Linux

程式语言:Python3.6+

依赖软件:ffmpeg、moviepy、tts api

2. 片头部分的制作

我这边使用了一个免费用于商业的开场视频作为片头的背景,然后将节目标题合成在视频中间。

实现这段片头的代码如下:


def create_header(title:str=’今日重磅新闻’, font_size:int=49):

   video = mpy.VideoFileClip(‘Globe.mp4’).set_fps(video_fps).resize(width=video_width)

   video = video.without_audio()

   subtitle = mpy.TextClip(title, font=title_font, fontsize=font_size, color=’white’)

   subtitle = subtitle.set_pos(‘center’).set_start(0.5).set_duration(video.duration – 2)

   final = mpy.CompositeVideoClip(

).subclip(0, video.duration – 1)

   return final


关于代码原理细节可以参看 moviepy 的文档说明进行了解。

3. 主体内容的制作

主体内容的视频部分和片头制作基本差不多,最大的区别仅仅是对用户输入文本的处理。关于文本的处理主要是为了规范输入文本的格式,以及确保文本显示在视频中不会出现越界的情况。

关于音频部分,我这边采用了一个基于亚马逊 tts 的二次开发 api,我将其封装成为一个名称为 to_speech 的函数方便进行调用。将整理好的文本行转换为音频然后下载的本地,调用 moviepy 载入并调整时间位置,以及裁切。最后把背景视频、文字内容、音频内容合成为一个 clip 对象。

主体部分的代码内容如下:


def create_content(text:str, font_size:int=28):

   get_char_r = lambda c: 0.9 if c in string.printable else 1.

   textlines = [line.strip() for line in text.split(‘\n’) if line.strip()]

   subtitles_contents = []

   for line in textlines:

       subtitle_content = ”

       width = 0

       for c in line:

           width += font_size * get_char_r(c)

           subtitle_content += c

           if width > video_width * 0.8:

               subtitle_content += ‘\n’

               width = 0

       subtitles_contents.append(subtitle_content.strip())

   video = mpy.VideoFileClip(‘World.mp4’).set_fps(video_fps).resize(width=video_width)

   video = video.without_audio()

   video_sub1 = video.subclip(0, 5)

   video_sub2 = video.subclip(5)

   video_sub2 = video_sub2.fx(mpy.vfx.speedx, 0.618)

   subtitles = []

   speeches = []

   subtitles_time = 0

   for i, text in enumerate(subtitles_contents):

       speech_filename = f’sp_{i}.mp3′

       to_speech(textlines[i] + ‘<break time=”1s”/>’, speech_filename)

       print(textlines[i])

       speech = mpy.AudioFileClip(speech_filename)

       speech = speech.subclip(0, speech.duration – 1)

       speeches.append(speech.set_start(subtitles_time))

       duration = speech.duration

       subtitle = mpy.TextClip(

           text, font=content_font, fontsize=font_size, color=’white’)

       subtitle = subtitle.set_pos(‘center’).set_duration(

           duration + 0.5).set_start(subtitles_time)

       subtitles.append(subtitle)

       subtitles_time += duration + 1

   video_sub2 = loop_video(

       video_sub2, subtitles_time – video_sub1.duration + 0.5).fadeout(0.5)

   video = mpy.concatenate_videoclips([video_sub1, video_sub2])

   audio = mpy.CompositeAudioClip(speeches)

   video = video.set_audio(audio)

   final = mpy.CompositeVideoClip(

+ subtitles)

   return final


4. 更多的元素内容

我们可以再编写额外的方法为主体部分增添其它的元素内容,例如:时间、水印、图标、投稿人名称等等。

下面这段代码用于增加视频左上方的水印:


def add_mark(clip, text:str=’喜马拉雅美国康州盘古农场’, font_size:int=21):

   subtitle = mpy.TextClip(text, font=mark_font, fontsize=font_size, color=’white’)

   subtitle = subtitle.set_pos((7, 7)).set_duration(clip.duration)

   final = mpy.CompositeVideoClip([clip, subtitle])

   return final


其它的元素内容的添加也可以参考这个方法来实现。

5. 视频渲染输出

完成上述一系列操作后就可以将片头和主体进行拼接然后渲染导出了。


final = mpy.concatenate([head_clip, body_clip])

final.write_videofile(output)


这次实践的内容非常简单,如果往后笔者在时间上宽裕,应该会将复杂可用的视频生成程序编写完成,敬请期待!

成品展示:

+1
0 评论
Inline Feedbacks
View all comments