· 

Python+GstreamerでH.264エンコーダ

Python+GstreamerでH.264エンコーダ

PythonとGstreamerでH.264ハードウェアエンコーダを使って動画圧縮をしてみました。

産業用カメラなどはデータ圧縮されていないものが多くその際にH.264ハードウェアエンコーダが活用できます。

環境

前回のブログ

GstreamerでRaspberryPi 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