Python+GstreamerでH.264エンコーダ
PythonとGstreamerでH.264ハードウェアエンコーダを使って動画圧縮をしてみました。
産業用カメラなどはデータ圧縮されていないものが多くその際にH.264ハードウェアエンコーダが活用できます。
環境
Gstreamerの動画操作の流れ
Gstreamerの大まかな流れは以下のようになります。
- 1.Gstreamerの初期化
- 2.パイプライン指定してインスタンス
- 3.ステートマシンの操作(PLAYINGやPAUSEDなどステートマシンを状況に応じて繰り返す)
1. Gstreamerの初期化
sysとgiをimportして、Gst.init(sys.argv)を実行します。
------------------------------------
import sys
import gi
import time
gi.require_version("Gst", "1.0")
from gi.repository import Gst
class camera:
def __init__(self):
# Gst.initでgstreamerの初期化
Gst.init(sys.argv)
2. パイプ指定してインスタンス
Gst.parse_launchを使ってgstreamerのパイプを指定します。
シェルからコマンドで使用するgst-launch-1.0のパイプと同じになります。
よってgst-launch-1.0で動作確認したあとにPythonにコピーしても良いかもです。
入力ソースのdef camera_serial_set(self)とtcambin name=binに関しては、通常は"/dev/video0"になるのですが、
The Imaging Source社のカメラではシリアル番号を設定することで複数カメラから個体のを指定できるようになっていて
このような形になります。
ついでなので動画は以下の2つを用意してみました。
mp4動画
mp4動画 + jpegパラパラ動画(HLS用)の同時処理
同時処理は、1つのソースに対してteeで分岐しmp4とjpegをそれぞれ非同期に生成するようにしています。
以下を前述のコードの下に追加します。
------------------------------------
# 複数個体の中からシリアル番号で個体を指定可能
def camera_serial_set(self):
self.camera = self.pipeline.get_by_name("bin")
self.camera.set_property("serial", '27120121')
# mp4動画
def mp4(self):
self.pipeline = Gst.parse_launch("tcambin name=bin ! video/x-bayer,width=640,height=480,framerate=30/1 \
! bayer2rgb \
! videoconvert \
! omxh264enc target-bitrate=10485760 control-rate=variable \
interval_intraframes=1 periodicty-idr=1 inline-header=FALSE \
! h264parse ! matroskamux ! filesink location=output.mp4")
self.camera_serial_set()
# mp4動画 + jpegパラパラ動画(HLS用)の同時処理
def mp4_jpeg(self):
self.pipeline = Gst.parse_launch("tcambin name=bin ! video/x-bayer,width=640,height=480, framerate=30/1 \
! bayer2rgb \
! tee name=t ! queue \
! videoconvert ! omxh264enc target-bitrate=10485760 control-rate=variable \
interval_intraframes=1 periodicty-idr=1 inline-header=FALSE \
! h264parse ! matroskamux ! filesink location=output.mp4 \
async=false t. ! queue \
! videorate ! video/x-raw,framerate=1/1 ! jpegenc quality=70 \
! hlssink max-files=10 target-duration=1 \
location=output%02d.jpeg playlist-location=output.m3u8")
self.camera_serial_set()
ステートマシンの操作
gstreamerのステートマシンは
- NULL -> READY -> PAUSED -> PLAYING、
- PLAYING -> PAUSED -> READY -> NULL
の順番でしか遷移できません。
ステートマシンの操作もこの順番を守る必要があります。
通常の録画スタートから終了とあわせてポーズと録画の間を繰り返して操作できるように以下のようなコードを準備します。
以下を前述のコードの下に追加します。
------------------------------------
def rec_start(self):
self.pipeline.set_state(Gst.State.READY)
self.pipeline.set_state(Gst.State.PAUSED)
self.pipeline.set_state(Gst.State.PLAYING)
def rec_fin(self):
self.pipeline.set_state(Gst.State.PAUSED)
self.pipeline.set_state(Gst.State.READY)
self.pipeline.set_state(Gst.State.NULL)
def pases2rec(self):
self.pipeline.set_state(Gst.State.PLAYING)
def rec2pases(self):
self.pipeline.set_state(Gst.State.PAUSED)
実際の録画
以下流れの録画をさせてみます。
- 録画スタート
- 5秒
- ポーズ
- 5秒
- 再録画
- 5秒
- 録画終了
以下を前述のコードの下に追加します。
------------------------------------
if __name__ == "__main__":
cam = camera()
# cam.mp4()
cam.mp4_jpeg()
cam.rec_start()
time.sleep(5)
cam.rec2pases()
time.sleep(5)
cam.pases2rec()
time.sleep(5)
cam.rec_fin()
------------------------------------
実行するとファイルが生成されていると思います。
- MP4動画
-
- output.mp4が4~5MB
- jpegパラパラ動画(HLS用)
-
- output.m3u8
- output??.jpeg
コメントをお書きください