GStreamerを使って、Webカメラから覗き窓っぽい画面を作る

#1.はじめに
GStreamerはエレメントと呼ばれる処理ブロックを繋げてストリーミング処理をするマルチメディアフレームワークです。

ドキュメントを見ていたらfisheyeというエレメントが気になりました。文字通り魚眼化するエレメントの様ですので、これを使って遊んでみようと思います。

#2.開発環境
筆者の環境はUbuntu 20.04です。下記コマンドで、GStreamer関連ライブラリをごっそり入れます。

```console
sudo apt-get install libgstreamer1.0-0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc \
gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 \
gstreamer1.0-qt5 gstreamer1.0-pulseaudio
```

またGStreamerアプリケーションのコンパイル用にlibtoolをインストールします。

```console
sudo apt install libtool-bin
```

#3.作成するGstreamerパイプライン
今回のパイプラインで使用するエレメント説明します。
<dl>
  <dt>v4l2src</dt>
  <dd>webカメラの映像取得するエレメント</dd>
  <dt>videoscale</dt>
  <dd>取得したWebカメラの映像を縮小するエレメント</dd>
  <dt>capsfilter</dt>
  <dd>videoscaleエレメントで拡縮するサイズを指定するエレメント</dd>
  <dt>videoconvert</dt>
  <dd>ビデオのフォーマット変換を行うエレメント</dd>
  <dt>fisheye</dt>
  <dd>魚眼化補正を行うエレメント</dd>
  <dt>ximagesink</dt>
  <dd>X11ウィンドウ上に出力するエレメント</dd>
</dl>

上述のエレメントで必要十分だと思っているのですが、過不足などありましたらコメントを頂けたら幸いです。

#4.コード

```fisheye.c
#include <gst/gst.h>
#include <glib.h>
#include <stdio.h>

int main (int   argc,
      char *argv[])
{
  GMainLoop *loop;

  GstElement *pipeline, *src, *vscale, *filter, *vconv, *fish, *sink;
  GstCaps *filtercaps;

  /* Initialisation */
  gst_init (&argc, &argv);

  loop = g_main_loop_new (NULL, FALSE);

  /* Create gstreamer elements */
  pipeline = gst_element_factory_make("pipeline",      "pipeline");
  src      = gst_element_factory_make("v4l2src",       "src");
  vscale   = gst_element_factory_make("videoscale",    "vscale");
  filter   = gst_element_factory_make("capsfilter",    "filter");
  vconv    = gst_element_factory_make("videoconvert",  "vconv");
  fish     = gst_element_factory_make("fisheye",       "fish");
  sink     = gst_element_factory_make("ximagesink",    "sink");

  if (!pipeline || !src || !vscale || !filter || !vconv || !fish || !sink) {
    g_printerr ("One element could not be created. Exiting.\n");
    return -1;
  }

  /* Set up the pipeline */

  /* we set the input web-cam to the source element */
  g_object_set (G_OBJECT (src), "device", "/dev/video0", "io-mode", 0, NULL);

  filtercaps = gst_caps_new_simple(
    "video/x-raw",
    "width",  G_TYPE_INT, 480,
    "height", G_TYPE_INT, 480,
    NULL);
  g_object_set (G_OBJECT(filter),"caps",filtercaps, NULL);

  g_object_set (G_OBJECT(sink),
                "sync",FALSE,
                NULL);

  /* we add all elements into the pipeline */
  gst_bin_add_many (GST_BIN (pipeline),
                    src, vscale, filter, vconv, fish, sink, NULL);

  /* we link all elements */
  gst_element_link_many (src, vscale, filter, vconv, fish, sink, NULL);

  /* Set the pipeline to "playing" state*/
  gst_element_set_state (pipeline, GST_STATE_PLAYING);

  /* Iterate */
  g_print ("Running...\n");
  g_main_loop_run (loop);

  /* Out of the main loop, clean up nicely */
  g_print ("Returned, stopping playback\n");
  gst_element_set_state (pipeline, GST_STATE_NULL);

  g_print ("Deleting pipeline\n");
  gst_object_unref (GST_OBJECT (pipeline));
  g_main_loop_unref (loop);

  return 0;
}
```
https://github.com/osamuraislice/gstreamer_study/blob/main/fisheye/fisheye.c

#5.コンパイルと実行

下記コマンドでコンパイルし、実行ファイルを生成します。

```console
libtool --mode=link gcc `pkg-config --cflags --libs gstreamer-1.0` -o fisheye fisheye.c
```

生成したファイルを実行します。

```console
./fisheye
```

次のように魚眼化されます。(PCのディスプレイをwebカメラで撮影したが、魚眼化して表示されている)
![browser.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693067/4316840d-9349-4f8a-12e3-fb68a488aab7.png)

近づいてカメラをのぞき込めば、玄関前に居る人みたいになります。
![kirby.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693067/c70885e6-4dcd-aa9e-4d83-a35c0d63434c.png)

#6.最後に
GStreamerは現在勉強中です。また面白いエレメントがあったら遊んでみます！
ここまで読んでいただいてありがとうございます。