libstreaming は、わずか数行のコードで、RTP over UDP を使用して Android 搭載デバイスのカメラやマイクをストリーミングできるようにする API です。
何らかのピアへのストリーミング セッションを開始するために実行する必要がある最初のステップは、「シグナリング」と呼ばれます。このステップでは、受信者に連絡し、受信ストリームの説明を送信します。 libstreaming でこれを行うには 3 つの方法があります。
API の完全な javadoc ドキュメントは、http://guigui.us/libstreaming/doc から入手できます。
Android では、周辺機器からエンコードされたデータを取得する方法が 3 つあります。
MediaRecorder API はストリーミング アプリケーションを目的としたものではありませんが、電話機の周辺機器からエンコードされたデータを取得するために使用できます。秘訣は、通常のファイルではなくLocalSocketに書き込むように MediaRecorder インスタンスを構成することです ( MediaStream.javaを参照)。
編集: Android Lollipop では、セキュリティ上の理由からLocalSocket を使用することはできなくなりました。ただし、 ParcelFileDescriptor を使用するとうまくいきます。詳細については、ファイルMediaStream.javaを参照してください。 (洞察力を提供してくれた人たちに感謝します)
このハックにはいくつかの制限があります。
このハッキングが携帯電話でどの程度うまく機能するかを判断するのは困難です。ただし、多くのデバイスでうまく動作します。
MediaCodec API には、先ほど述べた制限はありませんが、独自の問題があります。実際、MediaCodec API を使用するには、バッファーを使用する方法とサーフェスを使用する方法の 2 つがあります。
バッファ間メソッドは、 dequeueInputBufferおよび [ queueInputBuffer ](http://developer.android.com/reference/android/media/MediaCodec.html#queueInputBuffer(int, int, int, long, int)) への呼び出しを使用して、エンコーダに生データを供給します。それは簡単そうに思えますよね?この API でアクセスできるビデオ エンコーダは異なるカラー フォーマットを使用しており、それらをすべてサポートする必要があるため、そうではありません。これらのカラー形式のリストはここで入手できます。さらに、多くのエンコーダは、実際には適切にサポートしていないか、小さな問題が発生する可能性があるカラー形式のサポートを主張しています。
すべてのハードウェアパッケージは、これらの問題の解決に特化しています。特にEncoderDebuggerクラスを参照してください。
その API を使用したストリーミングが失敗した場合、libstreaming はMediaRecorder APIを使用したストリーミングにフォールバックします。
サーフェスからバッファへのメソッドは、createInputSurface() メソッドを使用します。この方法はおそらくカメラからの生のビデオをエンコードする最良の方法ですが、Android 4.3 以降が必要です。
glパッケージは、サーフェスで MediaCodec API を使用することに特化しています。
libstreaming ではデフォルトではまだ有効になっていませんが、 setStreamingMethod(byte)メソッドを使用して強制的に有効にすることができます。
周辺機器からの生データがエンコードされると、適切な RTP ストリームにカプセル化されます。使用する必要があるパケット化アルゴリズムはデータの形式 (H.264、H.263、AMR、および AAC) によって異なり、すべてそれぞれの RFC で指定されています。
上記の RFC のいずれかの基本的な実装を探している場合は、対応するクラスのソースを確認してください。
libstreaming のバージョン 2.0 以降、RTCP パケットも受信者に送信されます。送信者レポートのみが実装されます。これらは実際にはリップシンクに必要です。
rtpパッケージは、RTP パケット内のエンコードされたデータのパケット化を処理します。
< uses-permission android : name = " android.permission.INTERNET " />
< uses-permission android : name = " android.permission.WRITE_EXTERNAL_STORAGE " />
< uses-permission android : name = " android.permission.RECORD_AUDIO " />
< uses-permission android : name = " android.permission.CAMERA " />
この例は、この単純な Android アプリから抽出されたものです。これは、アクティビティ、フラグメント、またはサービスの一部である可能性があります。
protected void onCreate ( Bundle savedInstanceState ) {
...
mSession = SessionBuilder . getInstance ()
. setCallback ( this )
. setSurfaceView ( mSurfaceView )
. setPreviewOrientation ( 90 )
. setContext ( getApplicationContext ())
. setAudioEncoder ( SessionBuilder . AUDIO_NONE )
. setAudioQuality ( new AudioQuality ( 16000 , 32000 ))
. setVideoEncoder ( SessionBuilder . VIDEO_H264 )
. setVideoQuality ( new VideoQuality ( 320 , 240 , 20 , 500000 ))
. build ();
mSurfaceView . getHolder (). addCallback ( this );
...
}
public void onPreviewStarted () {
Log . d ( TAG , "Preview started." );
}
@ Override
public void onSessionConfigured () {
Log . d ( TAG , "Preview configured." );
// Once the stream is configured, you can get a SDP formated session description
// that you can send to the receiver of the stream.
// For example, to receive the stream in VLC, store the session description in a .sdp file
// and open it with VLC while streming.
Log . d ( TAG , mSession . getSessionDescription ());
mSession . start ();
}
@ Override
public void onSessionStarted () {
Log . d ( TAG , "Streaming session started." );
...
}
@ Override
public void onSessionStopped () {
Log . d ( TAG , "Streaming session stopped." );
...
}
@ Override
public void onBitrateUpdate ( long bitrate ) {
// Informs you of the bandwidth consumption of the streams
Log . d ( TAG , "Bitrate: " + bitrate );
}
@ Override
public void onSessionError ( int message , int streamType , Exception e ) {
// Might happen if the streaming at the requested resolution is not supported
// or if the preview surface is not ready...
// Check the Session class for a list of the possible errors.
Log . e ( TAG , "An error occured" , e );
}
@ Override
public void surfaceChanged ( SurfaceHolder holder , int format , int width ,
int height ) {
}
@ Override
public void surfaceCreated ( SurfaceHolder holder ) {
// Starts the preview of the Camera
mSession . startPreview ();
}
@ Override
public void surfaceDestroyed ( SurfaceHolder holder ) {
// Stops the streaming session
mSession . stop ();
}
SessionBuilder は、 Sessionオブジェクトの作成を容易にするだけです。ビデオ ストリーミングにはsetSurfaceViewの呼び出しが必要ですが、Android ではビデオを録画するために有効なサーフェスが必要であるため、これは驚くべきことではありません (これはMediaRecorder API の厄介な制限です)。 Android 4.3 では、 SurfaceViewを使用しないストリーミングは可能ですが、まだ実装されていません。 setContext(Context)の呼び出しが必要です。これにより、 H264StreamオブジェクトとAACStreamオブジェクトがSharedPreferences を使用してデータを保存および回復できるようになります。
Sessionオブジェクトは、あるピアへのストリーミング セッションを表します。これには、 start() (またはstop() ) メソッドが呼び出されたときに開始 (または停止) される 1 つ以上のStreamオブジェクトが含まれています。
getSessionDescription()メソッドは、セッションの SDP を文字列の形式で返します。呼び出す前に、セッションが設定されていることを確認する必要があります。 Session インスタンスでconfigure()またはstartPreview()を呼び出した後、コールバックonSessionConfigured()が呼び出されます。
上に示した例では、Session インスタンスは非同期方法で使用され、そのメソッドへの呼び出しはブロックされません。コールバックが呼び出されたときに、処理がいつ完了したかがわかります。
次のように、Session オブジェクトを同期的に使用することもできます。
// Blocks until the all streams are configured
try {
mSession . syncConfigure ();
} catch ( Exception e ) {
...
}
Strinf sdp = mSession . getSessionDescription ();
...
// Blocks until streaming actually starts.
try {
mSession . syncStart ();
} catch ( Exception e ) {
...
}
...
mSession . syncStop ();
Wiki のこのページと例 3 を確認してください。
< service android : name = " net.majorkernelpanic.streaming.rtsp.RtspServer " />
RtspServerをオーバーライドする場合は、上記の行をそれに応じて変更します。
Editor editor = PreferenceManager . getDefaultSharedPreferences ( this ). edit ();
editor . putString ( RtspServer . KEY_PORT , String . valueOf ( 1234 ));
editor . commit ();
確かにポートは設定に文字列として保存されますが、これには十分な理由があります。 EditTextPreference オブジェクトは入力を String として保存するため、それを Integer として保存するように簡単に構成することはできません (オーバーライドする必要があります)。
SessionBuilder . getInstance ()
. setSurfaceHolder ( mSurfaceView . getHolder ())
. setContext ( getApplicationContext ())
. setAudioEncoder ( SessionBuilder . AUDIO_AAC )
. setVideoEncoder ( SessionBuilder . VIDEO_H264 );
// Starts the RTSP server
context . startService ( new Intent ( this , RtspServer . class ));
// Stops the RTSP server
context . stopService ( new Intent ( this , RtspServer . class ));
このストリーミング スタックの使用方法とそのパフォーマンスを確認するには、この github ページにアクセスしてください。