読者です 読者をやめる 読者になる 読者になる

😃 mattintosh note 📝

Hello Raspberry Pi!

Raspberry Pi で GStreamer(gst-launch)

Raspberry Pi では OpenMAX のライブラリを使うことで高速に H264 エンコードができる。

現時点での Arch Linux ARM の ffmpeg は --enable-omx-rpi オプション付きでビルドされていないためエンコーダーに h264_omx が使えない。これは単純に ffmpeg をセルフビルドすれば済むが、omxplayer や GStreamer のそれに比べるとまだまだ性能を発揮できていないようにも感じる。

Raspberry Pi 用のカメラであれば raspivid で h264 で取り込みが出来るのでそこそこ負荷はかからないが、低価格な USB Web カメラは RAW か MJPEG にしか対応していないためハードウェアエンコードがほぼ必須となってくる。そこで、GStreamer を使って USB 接続した Web カメラの映像を取り込んでみることにした。

使うカメラは Buffalo の BSW20KM11BK。

カメラとマイクへのアクセス権を変更

まず、/dev/video0 に特権なしでカメラにアクセスできるようアカウントを video グループに追加する。

sudo usermod -a -G video $USER

マイクが認識されているか確認する。

arecord -l

ここでカメラのマイクが出てこない場合は特権で実行してみる。

sudo arecord -l

ここで出てくる場合は audio グループに入っていないのでこちらもグループに追加する。

sudo usermod -a -G audio $USER

一旦、ログアウトする。

デバイスを確認する

gst-device-monitor でデバイスを確認する。ビデオだけであれば v4l2-ctl --all でも良い。

※ssh -Y で接続しているとデバイスモニターが開始できないと怒られる。

gst-device-monitor-1.0
Probing devices... Device found: name : Genius WideCam F100 Analog Stereo class : Audio/Source caps : audio/x-raw, format=(string){ S16LE, S16BE, F32LE, F32BE, S32LE, S32BE, S24LE, S24BE, S24_32LE, S24_32BE, U8 }, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-alaw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-mulaw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; properties: alsa.resolution_bits = 16 device.api = alsa device.class = sound alsa.class = generic alsa.subclass = generic-mix alsa.name = "USB\ Audio" alsa.id = "USB\ Audio" alsa.subdevice = 0 alsa.subdevice_name = "subdevice\ \#0" alsa.device = 0 alsa.card = 0 alsa.card_name = USB_Camera alsa.long_card_name = "KYE\ Systems\ Corp.\ USB_Camera\ at\ usb-3f980000.usb-1.4\,\ high\ speed" alsa.driver_name = snd_usb_audio device.bus_path = platform-3f980000.usb-usb-0:1.4:1.2 sysfs.path = /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.2/sound/card0 udev.id = usb-KYE_Systems_Corp.USBCamera_200901010001-02 device.bus = usb device.vendor.id = 0458 device.vendor.name = "KYE\ Systems\ Corp.\ \(Mouse\ Systems\)" device.product.id = 708c device.product.name = "Genius\ WideCam\ F100" device.serial = KYE_Systems_Corp.USBCamera_200901010001 device.form_factor = webcam device.string = front:0 device.buffering.buffer_size = 352800 device.buffering.fragment_size = 176400 device.access_mode = mmap+timer device.profile.name = analog-stereo device.profile.description = "Analog\ Stereo" device.description = "Genius\ WideCam\ F100\ Analog\ Stereo" alsa.mixer_name = "USB\ Mixer" alsa.components = USB0458:708c module-udev-detect.discovered = 1 device.icon_name = camera-web-usb Device found: name : Monitor of Dummy Output class : Audio/Source caps : audio/x-raw, format=(string){ S16LE, S16BE, F32LE, F32BE, S32LE, S32BE, S24LE, S24BE, S24_32LE, S24_32BE, U8 }, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-alaw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-mulaw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; properties: device.description = "Monitor\ of\ Dummy\ Output" device.class = monitor device.icon_name = audio-input-microphone Device found: name : Dummy Output class : Audio/Sink caps : audio/x-raw, format=(string){ S16LE, S16BE, F32LE, F32BE, S32LE, S32BE, S24LE, S24BE, S24_32LE, S24_32BE, U8 }, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-alaw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-mulaw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; properties: device.description = "Dummy\ Output" device.class = abstract device.icon_name = audio-card Device found: name : USB_Camera class : Video/Source caps : video/x-raw, format=(string)YUY2, width=(int)1920, height=(int)1080, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, colorimetry=(string)2:4:7:1, framerate=(fraction)5/1; video/x-raw, format=(string)YUY2, width=(int)1280, height=(int)720, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, colorimetry=(string)2:4:7:1, framerate=(fraction)8/1; video/x-raw, format=(string)YUY2, width=(int)800, height=(int)600, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, colorimetry=(string)2:4:7:1, framerate=(fraction)10/1; video/x-raw, format=(string)YUY2, width=(int)640, height=(int)480, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, colorimetry=(string)2:4:7:1, framerate=(fraction)30/1; video/x-raw, format=(string)YUY2, width=(int)352, height=(int)288, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, colorimetry=(string)2:4:7:1, framerate=(fraction)30/1; video/x-raw, format=(string)YUY2, width=(int)320, height=(int)240, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, colorimetry=(string)2:4:7:1, framerate=(fraction)30/1; video/x-raw, format=(string)YUY2, width=(int)176, height=(int)144, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, colorimetry=(string)2:4:7:1, framerate=(fraction)30/1; video/x-raw, format=(string)YUY2, width=(int)160, height=(int)120, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, colorimetry=(string)2:4:7:1, framerate=(fraction)30/1; image/jpeg, width=(int)1920, height=(int)1080, pixel-aspect-ratio=(fraction)1/1, colorimetry=(string)2:4:7:1, framerate=(fraction)30/1; image/jpeg, width=(int)1280, height=(int)720, pixel-aspect-ratio=(fraction)1/1, colorimetry=(string)2:4:7:1, framerate=(fraction)30/1; image/jpeg, width=(int)800, height=(int)600, pixel-aspect-ratio=(fraction)1/1, colorimetry=(string)2:4:7:1, framerate=(fraction)30/1; image/jpeg, width=(int)640, height=(int)480, pixel-aspect-ratio=(fraction)1/1, colorimetry=(string)2:4:7:1, framerate=(fraction)30/1; image/jpeg, width=(int)352, height=(int)288, pixel-aspect-ratio=(fraction)1/1, colorimetry=(string)2:4:7:1, framerate=(fraction)30/1; image/jpeg, width=(int)320, height=(int)240, pixel-aspect-ratio=(fraction)1/1, colorimetry=(string)2:4:7:1, framerate=(fraction)30/1; image/jpeg, width=(int)176, height=(int)144, pixel-aspect-ratio=(fraction)1/1, colorimetry=(string)2:4:7:1, framerate=(fraction)30/1; image/jpeg, width=(int)160, height=(int)120, pixel-aspect-ratio=(fraction)1/1, colorimetry=(string)2:4:7:1, framerate=(fraction)30/1; video/x-raw, format=(string)I420, width=(int)1920, height=(int)1080, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)I420, width=(int)1280, height=(int)720, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)I420, width=(int)800, height=(int)600, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)I420, width=(int)640, height=(int)480, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)I420, width=(int)352, height=(int)288, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)I420, width=(int)320, height=(int)240, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)I420, width=(int)176, height=(int)144, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)I420, width=(int)160, height=(int)120, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)YV12, width=(int)1920, height=(int)1080, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)YV12, width=(int)1280, height=(int)720, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)YV12, width=(int)800, height=(int)600, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)YV12, width=(int)640, height=(int)480, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)YV12, width=(int)352, height=(int)288, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)YV12, width=(int)320, height=(int)240, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)YV12, width=(int)176, height=(int)144, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)YV12, width=(int)160, height=(int)120, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)BGR, width=(int)1920, height=(int)1080, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)BGR, width=(int)1280, height=(int)720, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)BGR, width=(int)800, height=(int)600, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)BGR, width=(int)640, height=(int)480, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)BGR, width=(int)352, height=(int)288, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)BGR, width=(int)320, height=(int)240, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)BGR, width=(int)176, height=(int)144, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)BGR, width=(int)160, height=(int)120, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)RGB, width=(int)1920, height=(int)1080, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)RGB, width=(int)1280, height=(int)720, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)RGB, width=(int)800, height=(int)600, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)RGB, width=(int)640, height=(int)480, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)RGB, width=(int)352, height=(int)288, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)RGB, width=(int)320, height=(int)240, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)RGB, width=(int)176, height=(int)144, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; video/x-raw, format=(string)RGB, width=(int)160, height=(int)120, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1; properties: udev-probed = true device.bus_path = platform-3f980000.usb-usb-0:1.4:1.0 sysfs.path = /sys/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/video4linux/video0 device.bus = usb device.subsystem = video4linux device.vendor.id = 0458 device.vendor.name = "KYE\\x20Systems\\x20Corp." device.product.id = 708c device.product.name = USB_Camera device.serial = KYE_Systems_Corp.USBCamera_200901010001 device.capabilities = :capture: device.api = v4l2 device.path = /dev/video0 v4l2.device.driver = uvcvideo v4l2.device.card = USB_Camera v4l2.device.bus_info = usb-3f980000.usb-1.4 v4l2.device.version = 263190 (0x00040416) v4l2.device.capabilities = 2233466881 (0x85200001) v4l2.device.device_caps = 85983233 (0x05200001)

今回使うカメラは RAW(YUY2/I420/YV12/RGB/BGR)か MJPEG に対応している。Raspberry Pi 用のカメラやちょっとお高めのウェブカメラは H264 に対応している。

この中で omxh264enc が対応しているのは I420 だけ?

ビデオエンコード

まずは入力を接続。qtmux か faac を使う場合は -e(EOF)がいるんだったかな…。

gst-launch-1.0 -v -e v4l2src device=/dev/video0

次にビデオのフォーマットを指定。

! video/x-raw, format=I420, width=1280, height=720, framerate=30/1

ビデオエンコーダを指定。パーサーも必要。

! omxh264enc ! h264parse

そして Muxer。

! qtmux

最後に sink。

! filesink location=sample.mp4

これを繋げると下のようになる。MP4 は正しく終了しないとコンテナがおかしくなるので timeout -s INT で割り込みをかけて正しく終了させる。

timeout -s INT 10 gst-launch-1.0 -v -e v4l2src device=/dev/video0 \
! video/x-raw, format=I420, width=1280, height=720, framerate=30/1 \
! omxh264enc ! h264parse \
! qtmux \
! filesink location=sample.mp4

ビットレートを指定する場合は target-bitrate= と control-rate= を使用する。target-bitrate= だけでは動かないので注意。あと、プロパティ間に ,(カンマ)も要らない。(なぜ仕様を合わせないのか…)

omxh264enc target-bitrate=2000000 control-rate=variable
gst-inspect-1.0 omxh264enc
Factory Details: Rank primary + 1 (257) Long-name OpenMAX H.264 Video Encoder Klass Codec/Encoder/Video Description Encode H.264 video streams Author Sebastian Dröge <sebastian.droege@collabora.co.uk> Plugin Details: Name omx Description GStreamer OpenMAX Plug-ins Filename /usr/lib/gstreamer-1.0/libgstomx.so Version 1.2.0 License LGPL Source module gst-omx Source release date 2014-07-23 Binary package GStreamer OpenMAX IL wrapper Plugin (ArchlinuxARM/RPi) Origin URL http://www.archlinuxarm.org/ GObject +----GInitiallyUnowned +----GstObject +----GstElement +----GstVideoEncoder +----GstOMXVideoEnc +----GstOMXH264Enc +----GstOMXH264Enc-omxh264enc Implemented Interfaces: GstPreset Pad Templates: SINK template: 'sink' Availability: Always Capabilities: video/x-raw width: [ 1, 2147483647 ] height: [ 1, 2147483647 ] framerate: [ 0/1, 2147483647/1 ] SRC template: 'src' Availability: Always Capabilities: video/x-h264 width: [ 16, 4096 ] height: [ 16, 4096 ] Element Flags: no flags set Element Implementation: Has change_state() function: gst_omx_video_enc_change_state Element has no clocking capabilities. Element has no URI handling capabilities. Pads: SINK: 'sink' Pad Template: 'sink' SRC: 'src' Pad Template: 'src' Element Properties: name : The name of the object flags: readable, writable String. Default: "omxh264enc-omxh264enc0" parent : The parent of the object flags: readable, writable Object of type "GstObject" control-rate : Bitrate control method flags: readable, writable, changeable only in NULL or READY state Enum "GstOMXVideoEncControlRate" Default: -1, "default" (0): disable - Disable (1): variable - Variable (2): constant - Constant (3): variable-skip-frames - Variable Skip Frames (4): constant-skip-frames - Constant Skip Frames (-1): default - Component Default target-bitrate : Target bitrate (0xffffffff=component default) flags: readable, writable, changeable in NULL, READY, PAUSED or PLAYING state Unsigned Integer. Range: 0 - 4294967295 Default: 4294967295 quant-i-frames : Quantization parameter for I-frames (0xffffffff=component default) flags: readable, writable, changeable only in NULL or READY state Unsigned Integer. Range: 0 - 4294967295 Default: 4294967295 quant-p-frames : Quantization parameter for P-frames (0xffffffff=component default) flags: readable, writable, changeable only in NULL or READY state Unsigned Integer. Range: 0 - 4294967295 Default: 4294967295 quant-b-frames : Quantization parameter for B-frames (0xffffffff=component default) flags: readable, writable, changeable only in NULL or READY state Unsigned Integer. Range: 0 - 4294967295 Default: 4294967295 inline-header : Inline SPS/PPS header before IDR flags: readable, writable, changeable only in NULL or READY state Boolean. Default: true periodicty-idr : Periodicity of IDR frames (0xffffffff=component default) flags: readable, writable, changeable only in NULL or READY state Unsigned Integer. Range: 0 - 4294967295 Default: 4294967295 interval-intraframes: Interval of coding Intra frames (0xffffffff=component default) flags: readable, writable, changeable only in NULL or READY state Unsigned Integer. Range: 0 - 4294967295 Default: 4294967295

次に faac。

gst-inspect-1.0 faac

これって src と sink 逆だと思うんだけど合ってるのか…?

Factory Details: Rank secondary (128) Long-name AAC audio encoder Klass Codec/Encoder/Audio Description Free MPEG-2/4 AAC encoder Author Ronald Bultje <rbultje@ronald.bitfreak.net> Plugin Details: Name faac Description Free AAC Encoder (FAAC) Filename /usr/lib/gstreamer-1.0/libgstfaac.so Version 1.8.3 License LGPL Source module gst-plugins-bad Source release date 2016-08-19 Binary package GStreamer Bad Plugins (Arch Linux) Origin URL http://www.archlinux.org/ GObject +----GInitiallyUnowned +----GstObject +----GstElement +----GstAudioEncoder +----GstFaac Implemented Interfaces: GstPreset Pad Templates: SRC template: 'src' Availability: Always Capabilities: audio/mpeg mpegversion: 4 channels: [ 1, 6 ] rate: { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 } stream-format: { adts, raw } base-profile: { main, lc, ssr, ltp } framed: true audio/mpeg mpegversion: 2 channels: [ 1, 6 ] rate: { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 } stream-format: { adts, raw } profile: { main, lc } framed: true SINK template: 'sink' Availability: Always Capabilities: audio/x-raw format: S16LE layout: interleaved rate: { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 } channels: 1 audio/x-raw format: S16LE layout: interleaved rate: { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 } channels: 2 channel-mask: 0x0000000000000003 audio/x-raw format: S16LE layout: interleaved rate: { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 } channels: 3 channel-mask: 0x0000000000000007 audio/x-raw format: S16LE layout: interleaved rate: { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 } channels: 4 channel-mask: 0x0000000000000107 audio/x-raw format: S16LE layout: interleaved rate: { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 } channels: 5 channel-mask: 0x0000000000000037 audio/x-raw format: S16LE layout: interleaved rate: { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 } channels: 6 channel-mask: 0x000000000000003f Element Flags: no flags set Element Implementation: Has change_state() function: gst_audio_encoder_change_state Element has no clocking capabilities. Element has no URI handling capabilities. Pads: SINK: 'sink' Pad Template: 'sink' SRC: 'src' Pad Template: 'src' Element Properties: name : The name of the object flags: readable, writable String. Default: "faac0" parent : The parent of the object flags: readable, writable Object of type "GstObject" perfect-timestamp : Favour perfect timestamps over tracking upstream timestamps flags: readable, writable Boolean. Default: false mark-granule : Apply granule semantics to buffer metadata (implies perfect-timestamp) flags: readable Boolean. Default: false hard-resync : Perform clipping and sample flushing upon discontinuity flags: readable, writable Boolean. Default: false tolerance : Consider discontinuity if timestamp jitter/imperfection exceeds tolerance (ns) flags: readable, writable Integer64. Range: 0 - 9223372036854775807 Default: 40000000 quality : Variable bitrate (VBR) quantizer quality in % flags: readable, writable Integer. Range: 1 - 1000 Default: 100 bitrate : Average Bitrate (ABR) in bits/sec flags: readable, writable Integer. Range: 8000 - 320000 Default: 128000 rate-control : Encoding bitrate type (VBR/ABR) flags: readable, writable Enum "GstFaacBrtype" Default: 1, "VBR encoding" (1): VBR encoding - VBR (2): ABR encoding - ABR tns : Use temporal noise shaping flags: readable, writable Boolean. Default: false midside : Allow mid/side encoding flags: readable, writable Boolean. Default: true shortctl : Block type encorcing flags: readable, writable Enum "GstFaacShortCtl" Default: 0, "Normal block type" (0): Normal block type - SHORTCTL_NORMAL (1): No short blocks - SHORTCTL_NOSHORT (2): No long blocks - SHORTCTL_NOLONG

ビデオとオーディオを組み合わせる(+いくつかのフィルタ)

フレームレートの変更は videorate フィルタを挟まなくてはならない。色空間の変換は autovideoconvert あたりでいいのだろうか?

clockoverlay は現在の時間を表示する。

ビデオとオーディオを結合する場合は queue を使うことになるが、Muxer へ接続する際に次のエレメントとの間に ! は使わない。Muxer などはデフォルトで name プロパティを持っている(qtmux なら qtmux0)が、これは上書きできる。

gst-launch-1.0 -v -e \
v4l2src device=/dev/video0 \
! videorate ! video/x-raw, format=I420, width=1280, height=720, framerate=15/1 ! clockoverlay \
! omxh264enc ! h264parse ! queue ! m. \
alsasrc device=hw:0 ! audio/x-raw, format=S16LE, rate=48000, channels=2 \
! faac ! aacparse ! queue ! m. \
qtmux name=m \
! filesink location=sample.mp4

この辺はスクリプトにして変数使ったほうがいいかもしれない。

VIDEO_SOURCE="v4l2src device=/dev/video0"
VIDEO_SOURCE_FORMAT="video/x-raw, format=I420, width=1280, height=720, framerate=30/1"
VIDEO_ENC="omxh264enc ! h264parse"
AUDIO_SOURCE="alsasrc device=hw:0"
AUDIO_SOURCE_FORMAT="audio/x-raw, format=S16LE, rate=48000, channels=2"
AUDIO_ENC="faac ! aacparse"
MUXER="qtmux"
SINK="filesink location=sample.mp4"

gst-launch-1.0 -v -e \
${VIDEO_SOURCE} ! ${VIDEO_SOURCE_FORMAT} ! ${VIDEO_ENC} ! queue ! qtmux0. \
${AUDIO_SOURCE} ! ${AUDIO_SOURCE_FORMAT} ! ${AUDIO_ENC} ! queue ! qtmux0. \
${MUXER} \
! ${SINK}

どっかにキューをもっと綺麗にまとめる書き方してたサイトがあったけどどこだっけ…。


Armadillo の解説サイトを読ませてもらったけどあれがなかったら覚えられなかったくらいわかりづらい。

あとは tcpserversink とかも覚えなければ…。ffmpeg なら -f v4l2 -i /dev/video0 とかでいいのに…ぐぬぬ。