わけあって文字だけ動画

嫌いでしょ? ワタシも嫌いだよ。

個人的な用事があって、「文字だけ動画を作るメモ」をこれから書くけれど、「おぉ、これで文字だけ動画を作れるぜっ、すんげー」と思うお方は死んでくれ。そういうことじゃない。

これの動機は続く投稿の方で使うんだけれど、「作り方」の方もなんだかんだ「書いとかないと忘れる」もんでね。けれども「日常使いになんかしないからスクリプトとして整理することなんかしない一時しのぎタスクだもの、メモだけで良かろ」てノリのシロモノ。

やり方は色々あるけれど、今ワタシが手持ちのものだと PyAV を使うのが一番手っ取り早いのでそれで:

雑だよ、20分以内で作ったヤツだからさ
 1 #! /bin/env python
 2 # -*- coding: utf-8 -*-
 3 import io
 4 import argparse
 5 
 6 from PIL import Image, ImageDraw, ImageFont
 7 import av  # https://github.com/mikeboers/PyAV
 8 
 9 
10 def _drawtextimage(width, height, txt1, fnt1, txt2, fnt2):
11     img = Image.new("RGB", (width, height), "#ffffff")
12     dctx = ImageDraw.Draw(img)
13 
14     txtsz = dctx.textsize(txt1, fnt1)
15     dctx.text(
16         (img.width / 2 - txtsz[0] / 2, img.height / 2 - txtsz[1] / 2),
17         txt1, font=fnt1, fill="#0000ff")
18 
19     txtsz = dctx.textsize(txt2, fnt2)
20     dctx.text(
21         (0, img.height - txtsz[1]),
22         txt2, font=fnt2, fill="#000000")
23 
24     del dctx  # destroy drawing context
25     return img
26 
27 
28 def _tovideo(args):
29     txt = io.open(
30         args.inputtextfile,
31         encoding="utf-8").read().replace("\n", " ").replace(" ", "")
32 
33     ocont = av.open(args.outfile, "w")
34     vrate = 12  # fps
35     vstream = ocont.add_stream('h264', rate=vrate)
36     vstream.width = 1280
37     vstream.height = 720
38     vstream.pix_fmt = 'yuv420p'
39 
40     fnt1 = ImageFont.truetype('msmincho.ttc', 576)
41     fnt2 = ImageFont.truetype('msmincho.ttc', 256)
42 
43     for c in txt:
44         for i in range(1, 13):
45             img = _drawtextimage(
46                 vstream.width, vstream.height, c, fnt1, "%2d" % i, fnt2)
47             vframe = av.VideoFrame.from_image(img)
48             for p in vstream.encode(vframe):
49                 ocont.mux(p)
50     try:
51         # flush the rest in queue.
52         for p in vstream.encode():
53             ocont.mux(p)
54     except av.AVError as e:  # End Of File
55         pass
56     ocont.close()  # MUST!
57 
58 
59 if __name__ == '__main__':
60     parser = argparse.ArgumentParser()
61     parser.add_argument("--outfile", default="banner_video.mp4")
62     parser.add_argument("inputtextfile")
63     args = parser.parse_args()
64 
65     _tovideo(args)

これで作った動画:

スクリプトを熟読すればわかると思うけれど、1280×720 の 12fps。この fps の意味も含め、続く投稿の方で動機は明らかにするけれど、先に言っておけば要は「検証やデバッグ・テスト目的の作為的な動画が欲しい」てことなのよ。一応この手のは「mpeg test streams」みたいな検索かければそれなりにはヒットするけれど、「自分の目的にあう」ものを簡単に見つけられるわけではない。なので簡単に自作することも時として必要だ、てこと。それだけの話。