libstreaming ist eine API, die es Ihnen mit nur wenigen Codezeilen ermöglicht, die Kamera und/oder das Mikrofon eines Android-Geräts per RTP über UDP zu streamen.
Der erste Schritt, den Sie ausführen müssen, um eine Streaming-Sitzung zu einem Peer zu starten, wird „Signalisierung“ genannt. In diesem Schritt kontaktieren Sie den Empfänger und senden eine Beschreibung der eingehenden Streams. Mit Libstreaming haben Sie drei Möglichkeiten, dies zu tun.
Die vollständige Javadoc-Dokumentation der API ist hier verfügbar: http://guigui.us/libstreaming/doc
Unter Android gibt es drei Möglichkeiten, verschlüsselte Daten von den Peripheriegeräten abzurufen:
Die MediaRecorder -API war nicht für Streaming-Anwendungen gedacht, kann aber zum Abrufen verschlüsselter Daten von den Peripheriegeräten des Telefons verwendet werden. Der Trick besteht darin, eine MediaRecorder-Instanz so zu konfigurieren, dass sie in einen LocalSocket statt in eine reguläre Datei schreibt (siehe MediaStream.java ).
Bearbeiten: Ab Android Lollipop ist die Verwendung eines LocalSocket aus Sicherheitsgründen nicht mehr möglich. Aber die Verwendung eines ParcelFileDescriptor reicht aus. Weitere Details in der Datei MediaStream.java ! (Danke an diese Jungs für den Einblick)
Dieser Hack hat einige Einschränkungen:
Es ist schwer zu sagen, wie gut dieser Hack auf einem Telefon funktionieren wird. Es funktioniert jedoch auf vielen Geräten gut.
Die MediaCodec- API weist nicht die gerade erwähnten Einschränkungen auf, weist jedoch ihre eigenen Probleme auf. Es gibt tatsächlich zwei Möglichkeiten, die MediaCodec-API zu verwenden: mit Puffern oder mit einer Oberfläche.
Die Puffer-zu-Puffer-Methode verwendet Aufrufe von dequeueInputBuffer und [ queueInputBuffer ](http://developer.android.com/reference/android/media/MediaCodec.html#queueInputBuffer(int, int, int, long, int)) an Versorgen Sie den Encoder mit Rohdaten. Das scheint einfach zu sein, oder? Das ist jedoch nicht der Fall, da Video-Encoder, auf die Sie mit dieser API zugreifen können, unterschiedliche Farbformate verwenden und Sie alle unterstützen müssen. Eine Liste dieser Farbformate finden Sie hier. Darüber hinaus behaupten viele Encoder, dass sie Farbformate unterstützen, die sie eigentlich nicht richtig unterstützen oder die zu kleinen Störungen führen können.
Das gesamte Hardware -Paket ist der Lösung dieser Probleme gewidmet. Siehe insbesondere die EncoderDebugger -Klasse.
Wenn das Streaming mit dieser API fehlschlägt, greift libstreaming auf das Streaming mit der MediaRecorder-API zurück.
Die Surface-to-Buffer-Methode verwendet die Methode createInputSurface(). Diese Methode ist wahrscheinlich die beste Möglichkeit, Rohvideos von der Kamera zu kodieren, erfordert jedoch Android 4.3 und höher.
Das gl -Paket ist für die Verwendung der MediaCodec-API mit einer Oberfläche vorgesehen.
Es ist in libstreaming noch nicht standardmäßig aktiviert, Sie können es jedoch mit der Methode setStreamingMethod(byte) erzwingen.
Sobald die Rohdaten von den Peripheriegeräten kodiert wurden, werden sie in einen geeigneten RTP-Stream gekapselt. Der zu verwendende Paketierungsalgorithmus hängt vom Format der Daten ab (H.264, H.263, AMR und AAC) und ist alle in ihrem jeweiligen RFC angegeben:
Wenn Sie nach einer Basisimplementierung eines der oben genannten RFCs suchen, prüfen Sie die Quellen der entsprechenden Klasse.
Seit Version 2.0 von libstreaming werden auch RTCP-Pakete an den Empfänger gesendet. Es sind nur Absenderberichte implementiert. Sie werden tatsächlich für die Lippensynchronisation benötigt.
Das RTP- Paket übernimmt die Paketierung codierter Daten in RTP-Paketen.
< 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 " />
Dieses Beispiel stammt aus dieser einfachen Android-App. Dies kann Teil einer Aktivität, eines Fragments oder eines Dienstes sein.
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 ();
}
Der SessionBuilder erleichtert einfach die Erstellung von Session -Objekten. Der Aufruf von setSurfaceView wird für das Video-Streaming benötigt, was keine Überraschung sein sollte, da Android eine gültige Oberfläche zum Aufzeichnen von Videos benötigt (dies ist eine ärgerliche Einschränkung der MediaRecorder- API). Unter Android 4.3 ist Streaming ohne SurfaceView möglich, aber noch nicht implementiert. Der Aufruf von setContext(Context) ist erforderlich, da er H264Stream -Objekten und AACStream- Objekten das Speichern und Wiederherstellen von Daten mithilfe von SharedPreferences ermöglicht.
Ein Session- Objekt stellt eine Streaming-Sitzung für einen Peer dar. Es enthält ein oder mehrere Stream- Objekte, die gestartet (bzw. gestoppt) werden, wenn die Methode start() (bzw. stop() ) aufgerufen wird.
Die Methode getSessionDescription() gibt ein SDP der Sitzung in Form eines Strings zurück. Bevor Sie es aufrufen, müssen Sie sicherstellen, dass die Sitzung konfiguriert wurde. Nach dem Aufruf von configure() oder startPreview() für Ihre Sitzungsinstanz wird der Rückruf onSessionConfigured() aufgerufen.
Im oben dargestellten Beispiel wird die Session-Instanz asynchron verwendet und Aufrufe ihrer Methoden blockieren nicht. Sie wissen, wann etwas erledigt ist, wenn Rückrufe aufgerufen werden.
Sie können ein Session-Objekt auch synchron wie folgt verwenden:
// 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 ();
Schauen Sie sich diese Seite des Wikis und das Beispiel 3 an.
< service android : name = " net.majorkernelpanic.streaming.rtsp.RtspServer " />
Wenn Sie RtspServer überschreiben möchten, ändern Sie die obige Zeile entsprechend.
Editor editor = PreferenceManager . getDefaultSharedPreferences ( this ). edit ();
editor . putString ( RtspServer . KEY_PORT , String . valueOf ( 1234 ));
editor . commit ();
Der Port ist tatsächlich als String in den Einstellungen gespeichert, dafür gibt es einen guten Grund. Das EditTextPreference-Objekt speichert seine Eingabe als String und kann nicht einfach (man müsste es überschreiben) so konfiguriert werden, dass es als Integer gespeichert wird.
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 ));
Besuchen Sie diese Github-Seite, um zu sehen, wie dieser Streaming-Stack verwendet werden kann und wie er funktioniert.