AndroidアプリでGstreamerを使ってみる

AndroidアプリでGstreamerを使う手順を紹介します。

下記の公式チュートリアルに従って進めます。

https://gstreamer.freedesktop.org/documentation/tutorials/android/index.html?gi-language=c

環境

Windows : 11

Android Studio : Arctic Fox | 2020.3.1 Patch4

Gstreamer : 1.18.5

Gstreamerを開発用PCにインストールする

公式サイトのインストール手順を参考に、開発用PCにGstreamerをインストールします。

(参考) Installing for Android development

https://gstreamer.freedesktop.org/documentation/installing/for-android-development.html?gi-language=c

Gstreamerを開発用PCにダウンロードします

https://gstreamer.freedesktop.org/data/pkg/android/

私は1.18.5をダウンロードしました。

https://gstreamer.freedesktop.org/data/pkg/android/1.18.5/

下記の圧縮ファイルををダウンロードし、7ZIPで解凍しました。

https://gstreamer.freedesktop.org/data/pkg/android/1.18.5/gstreamer-1.0-android-universal-1.18.5.tar.xz

7ZIPで解凍する方法は以下を参照してください。

https://armadillo.atmark-techno.com/howto/tar_xz-extract

※ 7ZIPは管理者権限で実行してください。管理者権限でないと、tarを解凍する時にアクセス権限が足りず失敗します。

NDKをインストールする

AndroidでC、C++を利用可能にするツールキットのNDK(Native Development Kit)をインストールします。

Tools > SDK Manager > SDK Toos でNDKにチェックを入れ、Applyを押下します。

※ 以下の画面キャプチャではv23をインストールしていますが、Gstreamer1.18.xの推奨はv21でしたので、v21を指定しましょう

チュートリアルをcloneする

githubからチュートリアルをcloneします。

https://github.com/enthusiasticgeek/Gstreamer_Android_Tutorials.git

Gstreamer1.18.xに対応しているのはこちらのリポジトリでした。

https://gitlab.freedesktop.org/gstreamer/gst-docs/-/tree/1.18

以降Tutorial-2までは、v18に対応していないチュートリアルを頑張って修正していますが、Tutorial-3の途中でリポジトリが間違っていることに気づいて使用するリポジトリを変えました。v18を使用する場合はTutorial-3の記載を参考にしてください。

Tutorial-1

「Gstreamer_Android_tutorials」には複数のチュートリアルが含まれています。

まずはTutorial-1のプロジェクトを開きます。

local.propertiesを開くと「sdk.dir」と「ndk.dir」が記載されていますが、「ndk.dir」は環境に合わせて修正できていないため、「sdk.dir」で指定されてフォルダの下にある「ndk\インストールしたndkバージョン」のフォルダを指定するように変更します。

sdk.dir=C\:\\Users\\username\\AppData\\Local\\Android\\Sdk
ndk.dir=C\:\\Users\\username\\AppData\\Local\\Android\\Sdk\\ndk\\23.1.7779620

次にndk-buidのタスクに環境変数「GSTREAMER_ROOT_ANDROID」を追加します。

task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {
    //def ndkDir = project.plugins.findPlugin('com.android.application').getNdkFolder()
    //def ndkDir = plugins.getPlugin('com.android.application').sdkHandler.ndkFolder
    def ndkDir = project.android.ndkDirectory

    //println(project.plugins.findPlugin('com.android.application').getNdkFolder())
    //println(plugins.getPlugin('com.android.application').sdkHandler.ndkFolder)
    println(project.android.ndkDirectory)


    //commandLine "/home/virgo/Android/Sdk/ndk-bundle/ndk-build/",

    environment GSTREAMER_ROOT_ANDROID: "C:/android/gstreamer-1.0-android-universal-1.18.5.tar/gstreamer-1.0-android-universal-1.18.5"

    commandLine "$ndkDir/ndk-build",
            'NDK_PROJECT_PATH=build',
            'APP_BUILD_SCRIPT=src/main/jni/Android.mk',
            'NDK_APPLICATION_MK=src/main/jni/Application.mk'


}

次にSyncしようとすると以下のエラーが起きる可能性があります。

Gradle sync failed: Unable to start the daemon process.
			The project uses Gradle 4.1 which is incompatible with Java 11 or newer.
			Possible solution:
			- Upgrade Gradle wrapper to 4.8 version and re-import the project
			(3 s 218 ms)

Android StudioでJava11以上を参照していると、Gradleのバージョンを4.8にアップグレードする必要があるので、project structureでGradleバージョンを4.8、プラグインのバージョンは対応する3.2.1にしてSyncします。

※ Android Studioを管理者権限で開いていない場合、gradle用のフォルダ作成でエラーになる可能性があるので、管理者権限で実行してください。

Syncが成功した後に私の環境でデバック実行すると、以下のエラーが起きました。

A problem occurred starting process 'command '

windowsの場合はndk-buidを実行するファイルの拡張子まで記載する必要があるので、build.gradleでndk-buildを実行している箇所に、拡張子を追記します。

commandLine "$ndkDir/ndk-build.cmd",
            'NDK_PROJECT_PATH=build',
            'APP_BUILD_SCRIPT=src/main/jni/Android.mk',
            'NDK_APPLICATION_MK=src/main/jni/Application.mk'

実行すると私の環境ではエラーが出ました。

clang++: error: invalid linker name in argument ‘-fuse-ld=gold.exe’

どうも私の環境にはgold.exeというリンカーがないようなので、以下のファイルにアクセスし

“C:\android\gstreamer-1.0-android-universal-1.18.5.tar\gstreamer-1.0-android-universal-1.18.5\armv7\share\gst-android\ndk-build\gstreamer-1.0.mk”

83行目の記載を以下に変更して、リンカーを指定しないようにしました。

GSTREAMER_LD                  := -Wl,-soname,lib$(GSTREAMER_ANDROID_MODULE_NAME).so

実行すると上記のエラーは解消されましたが、以下のエラーが出ました。

Transform output file C:\Users\username\AndroidStudioProjects\Gstreamer_Android_Tutorials\android-tutorial-1\app\build\libs\ndk-libs.jar does not exist.

ndkLibsToJarをndk-buidタスクの後に実行すれば回避できましたが、以下のエラーが出ました。

Could not resolve all files for configuration ':app:_internal_aapt2_binary'.

build.gradleのjcenterをmavenCentral()に変更し、allprojectsのrepositoriesにもgoogle()を追加することで回避できました。

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
//        jcenter()
        google()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
    }
}

allprojects {
    repositories {
//        jcenter()
        google()
        mavenCentral()
    }
}

次はエミュレータにマッチしたABIがないのでエラーが出ました。

The application could not be installed: INSTALL_FAILED_NO_MATCHING_ABIS

Android.mkとApplication.mkでABIを指定している箇所を、私が利用していたエミュレータのABIである「x86」に変更して実行したところ、ビルドが成功しました。

Android.mk

GSTREAMER_ROOT        := $(GSTREAMER_ROOT_ANDROID)/x86

Application.mk

APP_ABI := x86

Tutorial-2

Tutorial-1で実施したことを同様に実施します。

まず下記の設定をします。

  • gradleを4.8、pluginを3.2.1に変更する
  • jcenter()をmavenCentral()に変更する
  • repositoriesにgoogle()を追加する
  • ndk-buidのタスクに環境変数「GSTREAMER_ROOT_ANDROID」を追加する
  • ndk-buildのタスクでndk-buildをコマンドラインで実行するところに拡張子「.cmd」を追加する
  • local.propertiesのndkのパスを環境に合わせて修正する
  • (x86のエミュレータを利用する場合)Android.mkとApplication.mkでarmv7をしている箇所をx86に変更する

次に以下の順でデバックを開始します。

  • ndkBuildタスクを実行する
  • ndkLibsToJarタスクを実行する これはデバッグタスクで実行されるので個別の実行は不要なようです
  • デバッグ実行する

Tutorial-3~5

デバッグ実行したときにエラーが出ました。

java.lang.UnsatisfiedLinkError: dlopen failed: library “libc++_shared.so” not found

APKにlibc++_shared.soが入っていない場合に起きるエラーらしいです。

Application.mkに以下を追記してみましたが、エラーが解消しません。(Build > Analyze APKで確認しても、soファイルは含まれていませんでした)

APP_STL := c++_shared

https://developer.android.com/ndk/guides/cpp-support#selecting_a_c_runtime

以下のページで、Gstreamerのv18からdummy.cppを追加する必要があるとの記載がありました。

(参考) tutorials/android: Update for NDK r18 changes

https://gitlab.freedesktop.org/gstreamer/gst-docs/-/commit/5441a572d99375fb1a74d84dd3d619a8518d484f

上の記事通りにすると、このエラーが起きました。

make: *** No rule to make target ‘src/main/jni/dummy.cpp’, needed by ‘build/obj/local/x86/objs/tutorial-3/dummy.o’. Stop.

そして、このエラーの調査中に以下の記事をみて、v18に対応したチュートリアルのリポジトリがあることに気づき、

https://github.com/centricular/android_rtsp_example/issues/3

このリポジトリをcloneしました。

https://gitlab.freedesktop.org/gstreamer/gst-docs/-/tree/1.18

Tutorial-3をオープンするとビルドが成功しないので、まずgst-docs\examples\tutorial\androidでプロジェクトを開きます。

そして、gradleとプラグインのバージョンをを上げてビルドすると、以下の記事と同じエラーが出ます。

https://medium.com/swlh/lets-have-fun-gstreamer-android-tutorial-1-951ebfbb3f1e

記事通りに各問題を解消していけば解消しますが、NDKのバージョンは21.xxを指定しないと私の環境では動きませんでした。

次に、上記記事にないエラーが発生しました。

  Output:  error: resource android:style/TextAppearance.Material.Widget.Button.Borderless.Colored not found.
  error: resource android:style/TextAppearance.Material.Widget.Button.Colored not found.

ターゲットsdkをupgradeすることで解消できました。

targetSdkVersion 29

(参考) Material関連のエラーが出たので対処

https://qiita.com/shoma2da/items/1e84807809e7d1f4803b

Tutorial-3メモ

The check_initialization_complete() method is also augmented so that it requires a native window before considering GStreamer to be initialized:

⇒ SurfaceViewがないと初期化できない作りになっています。

data->pipeline = gst_parse_launch(“videotestsrc ! warptv ! videoconvert ! autovideosink “, &error);

  • videotestsrc : テスト用の動画データを作成する
  • warptv : サイケデリック(LSDなどの幻覚剤によってもたらされる心理的感覚や様々な幻覚、極彩色のグルグルと渦巻くイメージによって特徴づけられる視覚・聴覚の感覚の形容表現)なエフェクトをリアルタイムでつけられる
  • videoconvert : 動画のフレームのフォーマットを環境に適したものに変換してくれる
  • autovideosink : 画面に映像を出力する

(参考) GStreamer on macOS ではじめる動画処理【video編】

https://dev.classmethod.jp/articles/gstreamer-on-macos-video/#toc-7

Tutorial-4メモ

/* Build pipeline */
data->pipeline = gst_parse_launch ("playbin", &error);

playbinエレメントだけで、録画再生のパイプラインができる

Basic tutorial 12: Streaming has already shown how to adapt to the variable nature of the network bandwidth by using buffering. The same procedure is used here, by listening to the buffering messages:

ネットワークの帯域が狭い時は、バッファを利用することで対応できるそう。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です