🎃

【Android】AndroidでHLSストリーミング再生

2024/07/06に公開

はじめに

HLSをAndroidで受け取ってメディアプレイヤー再生したときの覚書き
メディアの再生にはandroidxのmedia3がメディアプレイヤー含め、かんたんに実装できそうだったのでこれを使った
ローカルのwebサーバー(flask)からhlsをダウンロードしてAndroidアプリ上のメディアプレイヤーから再生できることを確認した

hlsファイルの作成方法やファイル形式については、ここでは言及しないが、Androidが対応したものを使用するように注意する

実装

はじめにbuild.gradleにandroidxのmedia3への依存関係を追加する

dependencies {
    implementation 'androidx.media3:media3-exoplayer:1.3.1'
    implementation 'androidx.media3:media3-exoplayer-hls:1.3.1'
    implementation 'androidx.media3:media3-exoplayer-workmanager:1.3.1'
    implementation "androidx.media3:media3-exoplayer-dash:1.3.1"
    implementation "androidx.media3:media3-ui:1.3.1"
}

AndroidManifestはネットワーク関連の権限を追加しておく

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

ここは必要に応じてだが、今回はローカルのwebサーバー上のhlsファイルを参照したかったので、下記のnetwork_security_config.xmlを作成してres/xmlに置いておく
Androidはデフォルトではhttpアクセスを許可していないらしく、このようなファイルが必用だった(今回はローカルサーバーでテストだけ行いたく、https設定が面倒だったのでこのように設定した)
ちゃんとやりたい人はファイルへのアクセスはhttpsを推奨
(おそらくhttpsの場合はこちらは不要)

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>
</network-security-config>

メインのActivity実装コードは最後に載せておく
自分の場合は補足に記載したようなflaskのwebサーバーを立てていたので、
コード内の下記の箇所でアドレスとファイル名を指定してやればローカルのm3u8ファイルを参照してくれる

Uri hlsUri = Uri.parse("http://<your_address>:8000/video/<filename>.m3u8");

以下、コード全体

public class MainActivity extends AppCompatActivity {

    public PlayerView playerView;

    @OptIn(markerClass = UnstableApi.class)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ExoPlayer player = new ExoPlayer.Builder(this).build();

        playerView = findViewById(R.id.videoPlayer);
        player = new ExoPlayer.Builder(this).build();
        playerView.setPlayer(player);

        // HTTPデータソースファクトリを作成
        Factory dataSourceFactory = new Factory(this);

        // HLSメディアソースを作成
        Uri hlsUri = Uri.parse("http://<your_address>:8000/video/<filename>.m3u8");
        MediaItem mediaItem = MediaItem.fromUri(hlsUri);
        @OptIn(markerClass = UnstableApi.class) HlsMediaSource hlsMediaSource = new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItem);

        // プレイヤーにメディアソースを設定
        player.setMediaSource(hlsMediaSource);
        player.prepare();
        player.play();


    }
}

ちなみにレイアウトはメディアプレイヤーのみだが、こんな感じで記載した

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.media3.ui.PlayerView
        android:id="@+id/videoPlayer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:keepScreenOn="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

補足

今回はpython flaskを使ってかんたんにローカルにwebサーバーを立てて、AndroidStudioの仮想端末にhlsを配信した
一応、こちらのコードも載せておく
※アドレスは(0.0.0.0などではなく)実際のアドレスを設定した

from flask import Flask, send_from_directory, render_template
import os

app = Flask(__name__)

# ビデオファイルが保存されているディレクトリ
VIDEO_DIR = '/path/to/your/directory'

@app.route('/video/<path:filename>')
def stream_video(filename):
    return send_from_directory(VIDEO_DIR, filename)

if __name__ == '__main__':
    app.run(host='<your_address>', port=8000)

Discussion