2
1

More than 1 year has passed since last update.

Raspberry Pi 4Bに接続したUVCカメラのMJPEG画像をAmazon Kinesis Video Streamsにアップロード

Last updated at Posted at 2022-03-20

1. 概要

Raspberry Pi 4Bに接続したUVCカメラのMJPEG画像をAmazon Kinesis Video Streams(AWS KVS)にアップロードすることを試みた。

結論

この記事の時点で、MJPEG画像をAWS KVSにアップロードできていない。

背景

 知人からRaspberry Pi 3BでUVCカメラのMJPEG画像をAWS KVSにアプロードする方法について尋ねられた時、自分がやったことある手順やそのとき困ったこと情報を提供した。その後、知人はRaspberry Pi 4Bで試したところ、うまくいかないと連絡してきた。尚、UVCカメラはちょっと変わってる製品であるとのこと。
そこで、4Bが原因なのか、UVCカメラのせいなのか、連絡した手順が悪いのか確認することにした。

2. 準備

Raspberry Pi 4Bの準備

  • ラズベリーパイ財団のWebサイトのRaspberry Pi Imagerとか使う
  • Raspberry Pi OS(32bit)

Amazon Kinesis Video Stream の WebRTC のサンプルをビルドする

sudo apt-get install libcap2 libcap-dev
sudo apt-get install cmake pkg-config libssl-dev
sudo apt-get install gstreamer1.0-tools libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-omx gstreamer1.0-plugins-good gstreamer1.0-plugins-ugly

作業ディレクトリを作成し、移動

mkdir videocam
cd videocam

SDKのダウンロード

git clone --recursive https://github.com/awslabs/amazon-kinesis-video-streams-webrtc-sdk-c.git

ビルド用ディレクトリを作成してビルド

mkdir -p amazon-kinesis-video-streams-webrtc-sdk-c/build
cd amazon-kinesis-video-streams-webrtc-sdk-c/build
cmake ..

そこそこ時間かかる

make

UVCカメラの性能確認

video0 の部分は接続されている機器や数によって違うことがある。

Motion JPEGに対応していることがわかる。

pi@raspberrypi:build $ v4l2-ctl -d /dev/video0 --list-formats
ioctl: VIDIOC_ENUM_FMT
	Type: Video Capture

	[0]: 'MJPG' (Motion-JPEG, compressed)
	[1]: 'YUYV' (YUYV 4:2:2)

解像度やフレームレートの確認

pi@raspberrypi:build $ v4l2-ctl -d /dev/video0 --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
	Type: Video Capture

	[0]: 'MJPG' (Motion-JPEG, compressed)
		Size: Discrete 1920x1080
			Interval: Discrete 0.033s (30.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
			Interval: Discrete 0.033s (30.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
		Size: Discrete 1280x800
			Interval: Discrete 0.033s (30.000 fps)
		Size: Discrete 1280x720
			Interval: Discrete 0.033s (30.000 fps)
			Interval: Discrete 0.040s (25.000 fps)
			Interval: Discrete 0.050s (20.000 fps)
			Interval: Discrete 0.067s (15.000 fps)
			Interval: Discrete 0.100s (10.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
		Size: Discrete 800x600
			Interval: Discrete 0.033s (30.000 fps)
			Interval: Discrete 0.050s (20.000 fps)
			Interval: Discrete 0.067s (15.000 fps)
			Interval: Discrete 0.100s (10.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
		Size: Discrete 640x480
			Interval: Discrete 0.033s (30.000 fps)
			Interval: Discrete 0.050s (20.000 fps)
			Interval: Discrete 0.067s (15.000 fps)
			Interval: Discrete 0.100s (10.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
		Size: Discrete 640x360
			Interval: Discrete 0.033s (30.000 fps)
			Interval: Discrete 0.050s (20.000 fps)
			Interval: Discrete 0.067s (15.000 fps)
			Interval: Discrete 0.100s (10.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
		Size: Discrete 320x240
			Interval: Discrete 0.033s (30.000 fps)
			Interval: Discrete 0.050s (20.000 fps)
			Interval: Discrete 0.067s (15.000 fps)
			Interval: Discrete 0.100s (10.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
		Size: Discrete 1920x1080
			Interval: Discrete 0.033s (30.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
			Interval: Discrete 0.033s (30.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
	[1]: 'YUYV' (YUYV 4:2:2)
		Size: Discrete 1920x1080
			Interval: Discrete 0.200s (5.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
		Size: Discrete 1280x800
			Interval: Discrete 0.100s (10.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
		Size: Discrete 1280x720
			Interval: Discrete 0.100s (10.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
		Size: Discrete 800x600
			Interval: Discrete 0.067s (15.000 fps)
			Interval: Discrete 0.100s (10.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
		Size: Discrete 640x480
			Interval: Discrete 0.033s (30.000 fps)
			Interval: Discrete 0.040s (25.000 fps)
			Interval: Discrete 0.050s (20.000 fps)
			Interval: Discrete 0.067s (15.000 fps)
			Interval: Discrete 0.100s (10.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
		Size: Discrete 640x360
			Interval: Discrete 0.033s (30.000 fps)
			Interval: Discrete 0.050s (20.000 fps)
			Interval: Discrete 0.067s (15.000 fps)
			Interval: Discrete 0.100s (10.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
		Size: Discrete 320x240
			Interval: Discrete 0.033s (30.000 fps)
			Interval: Discrete 0.040s (25.000 fps)
			Interval: Discrete 0.050s (20.000 fps)
			Interval: Discrete 0.067s (15.000 fps)
			Interval: Discrete 0.100s (10.000 fps)
			Interval: Discrete 0.200s (5.000 fps)
		Size: Discrete 1920x1080
			Interval: Discrete 0.200s (5.000 fps)
			Interval: Discrete 0.200s (5.000 fps)

カメラの映像をモニターに映してみる。

gst-launch-1.0 v4l2src ! videoconvert ! ximagesink

出力されたので、カメラは動いており、Gstreamerも動作することが分かった。

3. Amazon Kinesis Video Streams(AWS KVS)に映像を送る

AWS用の環境変数

AWSにアカウントを作成したときのキーを設定する。

export AWS_ACCESS_KEY_ID=「アクセスキーID」
export AWS_SECRET_ACCESS_KEY=「シークレットアクセスキー」
export AWS_DEFAULT_REGION=「AWSリージョン」

とりあえずサンプルコードをそのまま動かしてみる。

現在の作業パスはビルドしたところから移動していない前提。

cd samples
./kvsWebrtcClientMasterGstSample test-ch

AWSへアクセスし、Kinesis Video Streams >シグナリングチャネルを開く。
メディア再生ビューワーで再生テストを行う。うまくいっていれば、UVCカメラの映像が見れる。
だが、みれない。これは前もそうだった気がする。サンプルコードそのままだとなぜかうまくいかない。

サンプルコードを変更して試す

amazon-kinesis-video-streams-webrtc-sdk-c/samples/kvsWebRTCClientMasterGstreamerSample.c
の 155行目付近を変更する。

エンコードやらフレームレートやらを変更してみる。変更箇所は以下。

if (pSampleConfiguration->useTestSrc) {
} else {
	ここのコード
}

ソフトウェアH.264エンコード, UVC Cam(YUV) -> H.264

上記に書いた箇所(elseの中)を以下に入れ替える。

pipeline = gst_parse_launch(
    "v4l2src do-timestamp=TRUE device=/dev/video0 is-live=TRUE ! queue ! videoconvert ! video/x-raw,width=1280,height=720,framerate=10/1 ! " 
    "x264enc bframes=0 speed-preset=veryfast bitrate=512 byte-stream=TRUE tune=zerolatency ! " 
    "h264parse config-interval=-1 ! video/x-h264,stream-format=byte-stream,alignment=au,profile=baseline ! appsink sync=TRUE emit-signals=TRUE name=appsink-video",
&error);

上の階層samplesに移動してもう一度ビルドし、サンプルアプリを実行する。
再びシグナリングチャネルをみると映像が再生された。カメラやGstreamer、AWS関係に問題はないようだ。

cd ..
cmake ..
make 
cd samples
./kvsWebrtcClientMasterGstSample test-ch

ハードウェアH.264エンコード, UVC Cam(YUV) -> H.264

同様にハードウェアH.264エンコードを試す。

pipeline = gst_parse_launch(
    "v4l2src device=/dev/video0 ! queue ! videoconvert ! video/x-raw,width=1280,height=720,framerate=10/1 ! " 
    "omxh264enc control-rate=1 target-bitrate=5120000 periodicty-idr=10 inline-header=FALSE ! " 
    "h264parse config-interval=-1 ! video/x-h264,stream-format=byte-stream,alignment=au,profile=baseline ! appsink sync=TRUE emit-signals=TRUE name=appsink-video",
&error);

ハードウェアH.264エンコード, UVC Cam(MJPEG) -> H.264

で、肝心のMJPEGをためす。

pipeline = gst_parse_launch(
    "v4l2src device=/dev/video0 ! image/jpeg,width=1280,height=720,framerate=10/1 ! omxmjpegdec ! " 
    "omxh264enc control-rate=1 target-bitrate=5120000 periodicty-idr=10 inline-header=FALSE ! " 
    "h264parse config-interval=-1 ! video/x-h264,stream-format=byte-stream,alignment=au,profile=baseline ! appsink sync=TRUE emit-signals=TRUE name=appsink-video",
&error);

結果は・・・ダメだった。以前、Raspberry Pi 3Bを使ったときはうまく言った記憶があるのだが・・・

4.原因を調べてみる

OMXは?

omxか?と思ったが、以下のコマンドによる確認で、omxmjpegdecとomxh264enc機能があることはわかった。

pi@raspberrypi:~ $ gst-inspect-1.0 | grep omx
omx:  omxmpeg2videodec: OpenMAX MPEG2 Video Decoder
omx:  omxmpeg4videodec: OpenMAX MPEG4 Video Decoder
omx:  omxh263dec: OpenMAX H.263 Video Decoder
omx:  omxh264dec: OpenMAX H.264 Video Decoder
omx:  omxtheoradec: OpenMAX Theora Video Decoder
omx:  omxvp8dec: OpenMAX VP8 Video Decoder
omx:  omxmjpegdec: OpenMAX MJPEG Video Decoder
omx:  omxvc1dec: OpenMAX WMV Video Decoder
omx:  omxh264enc: OpenMAX H.264 Video Encoder
omx:  omxanalogaudiosink: OpenMAX Analog Audio Sink
omx:  omxhdmiaudiosink: OpenMAX HDMI Audio Sink
libav:  avenc_h264_omx: libav OpenMAX IL H.264 video encoder encoder

3Bと4Bで何が違うの?

この違いはいったい・・・?
3Bではエラーが出ていない。だから3Bではうまくいき、4Bでは失敗しているということか?

Raspberry Pi 4B

pi@raspberrypi:~ $ gst-launch-1.0  v4l2src device=/dev/video0 ! image/jpeg,width=1280,height=720,framerate=10/1 ! omxmjpegdec! fakesink
パイプラインを一時停止 (PAUSED) にしています...
ERROR: Pipeline doesn't want to pause.
ERROR: from element /GstPipeline:pipeline0/GstOMXMJPEGDec-omxmjpegdec:omxmjpegdec-omxmjpegdec0: サポートライブラリを初期化できません
追加のデバッグ情報:
gstvideodecoder.c(2535): gst_video_decoder_change_state (): /GstPipeline:pipeline0/GstOMXMJPEGDec-omxmjpegdec:omxmjpegdec-omxmjpegdec0:
Failed to open decoder
Setting pipeline to NULL ...
Freeing pipeline ...

Raspberry Pi 3B

pi@raspberrypi:~ $ gst-launch-1.0  v4l2src device=/dev/video0 ! image/jpeg,width=1280,height=720,framerate=10/1 ! omxmjpegdec! fakesink
パイプラインを一時停止 (PAUSED) にしています...
Pipeline is live and does not need PREROLL ...
パイプラインを再生中 (PLAYING) にしています...
New clock: GstSystemClock

Gstreamerのエラーは何か?

GST_DEBUGを付けてログだししてみた

GST_DEBUG=FIXME gst-launch-1.0  v4l2src device=/dev/video0 ! image/jpeg,width=1280,height=720,framerate=10/1 ! omxmjpegdec!  fakesink

エラーログによると、gstomx.cでハンドル取得エラーらしい。これは自分や知人だけのエラーか、公式とかでも起こるのか、それが分からないが、多分みんな起きるのでは。
誰も使ってないのかMJPEGの機能・・・

0:00:00.219924812 20692   0x27cf80 ERROR  omx gstomx.c:799:gst_omx_component_new:<omxmjpegdec-omxmjpegdec0> Failed to get component handle 'OMX.broadcom.egl_render' from core '/opt/vc/lib/libopenmaxil.so': 0x80001000
0:00:00.219983719 20692   0x27cf80 WARN   videodecoder gstvideodecoder.c:2535:gst_video_decoder_change_state:<omxmjpegdec-omxmjpegdec0> error: Failed to open decoder
ERROR: Pipeline doesn't want to pause.
ERROR: from element /GstPipeline:pipeline0/GstOMXMJPEGDec-omxmjpegdec:omxmjpegdec-omxmjpegdec0: サポートライブラリを初期化できません
追加のデバッグ情報:
gstvideodecoder.c(2535): gst_video_decoder_change_state (): /GstPipeline:pipeline0/GstOMXMJPEGDec-omxmjpegdec:omxmjpegdec-omxmjpegdec0:

5. Pi4のOS再インストール

Gstreamerを更新しようとあれこれやっているうちにインストール済みパッケージの状態がおかしくなってきた。
そこで、OSの再インストールをした。深く考えずに使用中のSDカードにRaspberry Pi ImagerでRaspberry Pi OS 32bitを上書き。そして起動した。

5.1 違い

とりあえず本件関係の定番インストール。

sudo apt install autoconf automake libtool
sudo apt install gstreamer1.0-tools gstreamer1.0-plugins-good gstreamer1.0-plugins-ugly libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-plugins-bad

そして、確認。
GStreamerが1.14から1.18へ更新されてる!知らぬ間に公式で更新されていた?これで全て解決?

pi@raspberrypi:~ $ gst-launch-1.0 --version
gst-launch-1.0 version 1.18.4
GStreamer 1.18.4

と思ったら、omxmjpegdecがいない。あんなにたくさんいたomxがいない。

pi@raspberrypi:~ $ gst-inspect-1.0 | grep omx
libav:  avenc_h264_omx: libav OpenMAX IL H.264 video encoder encoder
libav:  avenc_mpeg4_omx: libav OpenMAX IL MPEG-4 video encoder encoder

今後

最新ソースもってきて自分でビルドか、自分でソース修正してみたいところ。
2022/03/27 : ソースのビルドの作業過程でOS再インストールしたら余計にハマった。

2
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1