iMacでいろいろ動画エンコード
環境
素材
以下の3つの素材を1920x1080 29.97P に変換する速度を測ります。
- sony_xavcs_30p.MP4
- 1920 × 1080 29.97fps
- 50Mbps
- Sony RX100M4 X-AVCS
- 11175F
- 6分13秒
- canon_uhd.MP4
- gh5_422_uhd.MP4
- 3840x2160 29.97fps
- 150Mbps
- LUMIX GH5
- 1770F
- 59秒
FFmpeg編
FFmpegはバージョン4.2.2を使用します。
Input | Codec | FPS |
---|---|---|
sony_xavcs_30p.MP4 | libx264 | 31 |
↑ | h264_videotoolbox | 202 |
↑ | libx265 | 11 |
canon_uhd.MP4 | libx264 | 11 |
↑ | h264_videotoolbox | 53 |
↑ | libx265 | 4.68 |
gh5_422_uhd.MP4 | libx264 | 11 |
↑ | h264_videotoolbox | 42 |
↑ | libx265 | 5.0 |
h264_videotoolboxはmacOSでハードウェアエンコード出来るオプションですが、かなり早いです。
ffmpeg -y -i sony_xavcs_30p.MP4 -c:v libx264 -b:v 5000k fhd2fhd_x264_1.mp4 ffmpeg -y -i sony_xavcs_30p.MP4 -c:v h264_videotoolbox -b:v 5000k fhd2fhd_toolbox_h264_1.mp4 ffmpeg -y -i sony_xavcs_30p.MP4 -c:v libx265 -b:v 5000k fhd2fhd_x265_1.mp4 ffmpeg -y -i canon_uhd.MP4 -c:v libx264 -b:v 5000k uhd2fhd_x264_1.mp4 ffmpeg -y -i canon_uhd.MP4 -c:v h264_videotoolbox -b:v 5000k uhd2fhd_toolbox_h264_1.mp4 ffmpeg -y -i canon_uhd.MP4 -c:v libx265 -b:v 5000k uhd2fhd_h265_1.mp4 ffmpeg -y -i gh5_422_uhd.MP4 -c:v libx264 -b:v 5000k -pix_fmt yuv420p uhd422_to_fhd_x264_1.mp4 ffmpeg -y -i gh5_422_uhd.MP4 -c:v h264_videotoolbox -b:v 5000k -pix_fmt yuv420p uhd422_to_fhd_toolbox_h264_1.mp4 ffmpeg -y -i gh5_422_uhd.MP4 -c:v libx265 -b:v 5000k -pix_fmt yuv420p uhd422_to_fhd_h265_1.mp4
Adobe Media Encoder編
Input | Codec | Min:Sec | FPS |
---|---|---|---|
sony_xavcs_30p.MP4 | H.264 | 1:19 | 141 |
↑ | HEVC(H.265) | 4:18 | 43 |
canon_uhd.MP4 | H.264 | 1:53 | 12 |
↑ | HEVC(H.265) | 2:02 | 11 |
gh5_422_uhd.MP4 | H.264 | 2:31 | 11 |
↑ | HEVC(H.265) | 2:43 | 10 |
上記はAdobeのMedia Encoder 14.1 でのエンコード結果です。H.264はMetal ハードウェアエンコード、H.265はCPUでのエンコードになります。 気になる点はH.265はFFmpegの3倍ほどの速度が出ています。Finder情でもQuickTimeが再生可能な形式なので、違うエンコード結果になっている模様です。
FHDのエンコードは、エンコーダの性能が速度を決める模様です。 UHDはエンコーダに依らず、デコード処理がボトルネックになっているかもしれません。
Prometheus始めてみる
以下のVagrantファイルでイメージを作ります。
# -*- mode: ruby -*- # vi: set ft=ruby : Vagrant.configure("2") do |config| config.vm.box = "centos/8" # https://github.com/dotless-de/vagrant-vbguest/issues/367 config.vm.box_url = "http://cloud.centos.org/centos/8/x86_64/images/CentOS-8-Vagrant-8.1.1911-20200113.3.x86_64.vagrant-virtualbox.box" config.vm.network "private_network", ip: "192.168.33.30" config.vm.provision "shell", inline: <<-SHELL mv /etc/localtime /etc/localtime.bak ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime sed -i "/SELINUX/s/enforcing/disabled/g" /etc/selinux/config yum install -y java-11-openjdk SHELL # config.vm.synced_folder "/Users/tak/Documents/program/vagrant/prometheus_vagrant", "/mnt/shared" end
イメージが出来たらこちらの記事を参考にPrometheusをインストールします。
インストールに成功すると以下のURLで状況が見れるようになります。
http://192.168.33.30:9090/graph
次に下のJavaがExporterになります。メモリの状況を通知するプロセスです。
import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpServer; import java.io.IOException; import java.net.InetSocketAddress; public class ExporterTest1 { private static final int EXPOSE_PORT = 9092; public static void main(String[] args) throws IOException { var server = HttpServer.create(new InetSocketAddress(EXPOSE_PORT), 0); var context = server.createContext("/"); context.setHandler(ExporterTest1::handleRequest); System.out.println("started at " + EXPOSE_PORT); server.start(); } private static void handleRequest(HttpExchange exchange) throws IOException { var body = ""; Runtime runtime = Runtime.getRuntime(); body += "java_runtime_free_memory\t" + runtime.freeMemory() + "\n"; var response = body.getBytes(); exchange.sendResponseHeaders(200, response.length); var output = exchange.getResponseBody(); output.write(response); output.close(); } }
次は設定ファイルを変更します。
$ sudo vi /usr/prometheus/prometheus.yml + - job_name: 'exporter_test' + static_configs: + - targets: ['localhost:9092'] $ sudo systemctl restart prometheus
Prometheusの上部から Status->Targetをみると この様に認識されました。 TOPに戻って java_runtime_free_memory -> execute -> grapthでグラフが表示されればOKです。
MinikubeでKubernetesを試す
まずは Vagrant でイメージを作成します。
# -*- mode: ruby -*- # vi: set ft=ruby : Vagrant.configure("2") do |config| config.vm.box = "bento/ubuntu-19.10" config.vm.provider "virtualbox" do |vb| vb.cpus = "2" end config.vm.network "private_network", ip: "192.168.33.100" config.vm.provision "shell", inline: <<-SHELL curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.9.0/bin/linux/amd64/kubectl chmod +x ./kubectl mv ./kubectl /usr/local/bin/kubectl curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.24.1/minikube-linux-amd64 chmod +x minikube mv minikube /usr/local/bin/ minikube version kubectl version curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable" apt-get install docker-ce docker-ce-cli containerd.io -y ufw disable SHELL end
起動します。
vagrant up vagrant ssh
イメージ内で起動するプロセスを作ります。
git clone https://github.com/kubernetes-up-and-running/kuard.git cd kuard sudo make sed -ie 's/FROM ARG_FROM/FROM alpine/' Dockerfile.kuard sed -ie 's/ARG_FAKEVER\/ARG_ARCH/blue\/amd64/' Dockerfile.kuard sudo docker build -t kuard-run:1 . -f Dockerfile.kuard
sudo docker run -d --name kuard -p 8080:8080 kuard-run:1
ブラウザで http://192.168.33.100:8080/ を開いてみます。
多分このような画面が出ると思います。
sudo docker stop kuard
で停止します。
Kubernetesを使います。
export CHANGE_MINIKUBE_NONE_USER=true sudo -E minikube start --vm-driver=none
まず状態を確認します。
$ minikube status minikube: Running cluster: Running kubectl: Correctly Configured: pointing to minikube-vm at 127.0.0.1 $ kubectl get node NAME STATUS ROLES AGE VERSION vagrant Ready <none> 15m v1.8.0 $ kubectl get pods No resources found.
Podを作ります。
$ kubectl run kuard --image=kuard-run:1 deployment "kuard" created $ kubectl get pods NAME READY STATUS RESTARTS AGE kuard-86d4765c69-4crbk 1/1 Running 0 7m
とりあえず一旦削除します。
kubectl delete deployments/kuard
kuard.yml を用意します。
apiVersion: v1 kind: Pod metadata: name: kuard spec: containers: - name: kuard image: kuard-run:1 ports: - containerPort: 8080 name: http protocol: TCP
Podが作成されているのを確認します。
$ kubectl get pods NAME READY STATUS RESTARTS AGE kuard 1/1 Running 0 1m $ kubectl describe pods kuard Name: kuard Namespace: default Node: vagrant/10.0.2.15 Start Time: Sat, 22 Feb 2020 13:19:44 +0000 Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"kuard","namespace":"default"},"spec":{"containers":[{"image":"kuard-run:1","name":... Status: Running IP: 172.17.0.4 Containers: kuard: Container ID: docker://7b17419be3b56fb76e3539a0702782b9a7749252b214d859143064a7eb2aa1ab Image: kuard-run:1 Image ID: docker://sha256:d4081f1dfbe6f426cd1ac49dbb16b2f073e5d18af7022e03fa2c674b77b7f7f4 Port: 8080/TCP State: Running Started: Sat, 22 Feb 2020 13:19:45 +0000 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-hkpw5 (ro) Conditions: Type Status Initialized True Ready True PodScheduled True Volumes: default-token-hkpw5: Type: Secret (a volume populated by a Secret) SecretName: default-token-hkpw5 Optional: false QoS Class: BestEffort Node-Selectors: <none> Tolerations: <none> Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 1m default-scheduler Successfully assigned kuard to vagrant Normal SuccessfulMountVolume 1m kubelet, vagrant MountVolume.SetUp succeeded for volume "default-token-hkpw5" Normal Pulled 1m kubelet, vagrant Container image "kuard-run:1" already present on machine Normal Created 1m kubelet, vagrant Created container Normal Started 1m kubelet, vagrant Started container $ kubectl logs kuard 2020/02/22 13:19:45 Starting kuard version: v0.10.0-blue
Podを削除します。
$ kubectl delete pods/kuard pod "kuard" deleted
以上です。
Selenium RemoteWebDriver を試してみる
クライアントPCの上で仮想環境を構築し、その上でSeleniumを動かします。 まずはVagrantで仮想マシンを作成します。
# -*- mode: ruby -*- Vagrant.configure("2") do |config| config.vm.box = "bento/ubuntu-19.10" config.vm.network "private_network", ip: "192.168.33.10" config.vm.provision "shell", inline: <<-SHELL apt-get update -y apt update -y apt install fonts-ipafont fonts-ipaexfont default-jdk unzip -y # Install Google Chrome wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list apt update -y apt install google-chrome-stable -y # Install Selenium Environment mkdir /home/vagrant/selenium cd /home/vagrant/selenium wget https://chromedriver.storage.googleapis.com/80.0.3987.16/chromedriver_linux64.zip unzip chromedriver_linux64.zip wget https://selenium-release.storage.googleapis.com/3.141/selenium-server-standalone-3.141.59.jar SHELL end
vagrant up
仮想環境内でHubとNodeの2つのプロセスを立ち上げます。HubとNodeは1:Nの関係になるようです。
Hub
$ cd selenium/ $ DISPLAY=:99.0 java -Dwebdriver.gecko.driver=geckodriver -jar selenium-server-standalone-3.141.59.jar -role hub
Node
$ DISPLAY=:99.0 java -Dwebdriver.gecko.driver=geckodriver -jar selenium-server-standalone-3.141.59.jar -role node -hub http://localhost:4444
http://192.168.33.10:4444/grid/console をブラウザで開くと現在の状況が確認できます。
Seleniumのコードを用意します。
import org.junit.After import org.junit.Before import org.junit.Test import org.openqa.selenium.OutputType import org.openqa.selenium.TakesScreenshot import org.openqa.selenium.WebDriver import org.openqa.selenium.chrome.ChromeOptions import org.openqa.selenium.remote.RemoteWebDriver import java.io.File import java.net.URL class RemoteTest { var driver: WebDriver? = null @Before fun setup() { // val option = FirefoxOptions() // 今は使えない val option = ChromeOptions() option.setHeadless(true); driver = RemoteWebDriver(URL("http://192.168.33.10:4444/wd/hub"), option) } @Test fun test1() { driver!!.get("https://www.yahoo.co.jp/"); val ss = (driver as TakesScreenshot).getScreenshotAs(OutputType.FILE) ss.renameTo(File("./yahoo_top.png")) } @After fun dispose() { if (driver != null) { driver!!.quit(); } } }
実行するとホスト側のルートディレクトリにスクリーンショットが保存されます。
問題なく実行できました。
Intel DL boostを使おうとした続き
先日の記事ですが、問題解決できました。
#include <immintrin.h> #include <stdio.h> int main() { int8_t __attribute__((aligned(64))) op1_int8[64]; int8_t __attribute__((aligned(64))) op2_int8[64]; int __attribute__((aligned(64))) op3_int[16]; int __attribute__((aligned(64))) presult[16]; int16_t __attribute__((aligned(64))) op4_int16[32]; int16_t __attribute__((aligned(64))) op5_int16[32]; __m512i v1_int8; __m512i v2_int8; __m512i v3_int; __m512i v4_int16; __m512i v5_int16; for (int i = 0;i < 64;i++) { op1_int8[i] = i; op2_int8[i] = i; } for (int i = 0;i < 16;i++) { op3_int[i] = 0; } for (int i = 0;i < 32;i++) { op4_int16[i] = i; op5_int16[i] = i; } v1_int8 = _mm512_load_si512(&op1_int8); v2_int8 =_mm512_load_si512(&op2_int8); v3_int = _mm512_load_si512(&op3_int); v4_int16 = _mm512_load_si512(&op4_int16); v5_int16 = _mm512_load_si512(&op5_int16); printf("vpdpbusds\n"); __m512i result = _mm512_dpbusds_epi32(v3_int, v1_int8, v2_int8); _mm512_store_si512(presult, result); for (int i = 0; i < 16; i++) { int val = presult[i]; printf("%d = %d\n", i, val); } printf("vpmaddwd + vpaddd\n"); result = _mm512_madd_epi16(v4_int16, v5_int16); result = _mm512_add_epi32(result, v3_int); _mm512_store_si512(presult, result); for (int i = 0; i < 16; i++) { int val = presult[i]; printf("%d = %d\n", i, val); } return 0; }
実行結果
vpdpbusds 0 = 14 1 = 126 2 = 366 3 = 734 4 = 1230 5 = 1854 6 = 2606 7 = 3486 8 = 4494 9 = 5630 10 = 6894 11 = 8286 12 = 9806 13 = 11454 14 = 13230 15 = 15134 vpmaddwd + vpaddd 0 = 1 1 = 13 2 = 41 3 = 85 4 = 145 5 = 221 6 = 313 7 = 421 8 = 545 9 = 685 10 = 841 11 = 1013 12 = 1201 13 = 1405 14 = 1625 15 = 1861
なんか vpmaddwd + vpaddd の使い方間違っている気がしますが、気にしない方針で
Intel DL boostを使おうとしたけど
EC2 c5.12xlarge インスタンスでは使えるはずと思って試しました。 Intelのサイトを参考に
sudo apt install gcc-8 clang-8
#include <immintrin.h> #include <stdio.h> int main() { int8_t __attribute__((aligned(64))) op1_int8[64]; int8_t __attribute__((aligned(64))) op2_int8[64]; int __attribute__((aligned(64))) op3_int[16]; int16_t __attribute__((aligned(64))) op4_int16[32]; __m512i v1_int8; __m512i v2_int8; __m512i v3_int; __m512i v4_int16; printf("size of int8_t is %zu\n", sizeof(int8_t)); printf("size of int is %zu\n", sizeof(int)); printf("size of int16_t is %zu\n", sizeof(int16_t)); for (int i = 0;i < 64;i++) { op1_int8[i] = i; op2_int8[i] = i; } for (int i = 0;i < 16;i++) { v3_int[i] = 0; } for (int i = 0;i < 32;i++) { v4_int16[i] = 0; } v1_int8 =_mm512_load_si512(&op1_int8); v2_int8 =_mm512_load_si512(&op2_int8); v3_int =_mm512_load_si512(&op3_int); v4_int16 =_mm512_load_si512(&op4_int16); __m512i result = _mm512_dpbusds_epi32(v3_int, v1_int8, v2_int8); int* presult = (int*) &result; for (int i = 0; i < 16; i++) { printf("%d = %d\n", i, presult[i]); } return 0; }
gcc-8 -mavx512f -march=icelake-server main.c -o main
実行結果が以下の通り
size of int8_t is 1 size of int is 4 size of int16_t is 2 0 = 15 1 = 126 2 = 1135245462 3 = 33463 4 = 1135244750 5 = 34583 6 = 2607 7 = 3486 8 = 1135208014 9 = 38359 10 = 1133029965 11 = 41015 12 = 1135254878 13 = 44183 14 = 13230 15 = 15134
明らかに計算結果が違っています。 原因調査中・・・
AVX-512 Vector Neural Network Instructions (VNNI) - x86 - WikiChip