libstreaming — это API, который позволяет вам с помощью всего лишь нескольких строк кода осуществлять потоковую передачу с камеры и/или микрофона устройства на базе Android, используя RTP через UDP.
Первый шаг, который вам нужно будет выполнить, чтобы начать сеанс потоковой передачи с каким-либо одноранговым узлом, называется «сигнализацией». На этом этапе вы свяжетесь с получателем и отправите описание входящих потоков. У вас есть три способа сделать это с помощью libstreaming.
Полная документация API по Javadoc доступна здесь: http://guigui.us/libstreaming/doc.
В Android есть три способа получить закодированные данные с периферийных устройств:
API MediaRecorder не предназначен для приложений потоковой передачи, но может использоваться для получения закодированных данных с периферийных устройств телефона. Хитрость заключается в том, чтобы настроить экземпляр MediaRecorder для записи в LocalSocket вместо обычного файла (см. MediaStream.java ).
Изменить: начиная с Android Lollipop использование LocalSocket больше невозможно по соображениям безопасности. Но использование ParcelFileDescriptor помогает. Подробнее в файле MediaStream.java ! (Спасибо этим ребятам за понимание)
Этот хак имеет некоторые ограничения:
Трудно сказать, насколько хорошо этот хак будет работать на телефоне. Хотя он хорошо работает на многих устройствах.
API MediaCodec не имеет ограничений, о которых я только что упомянул, но имеет свои проблемы. На самом деле существует два способа использования API MediaCodec: с буферами или с поверхностью.
Метод буфер-буфер использует вызовы dequeueInputBuffer и [ queueInputBuffer ](http://developer.android.com/reference/android/media/MediaCodec.html#queueInputBuffer(int, int, int, long, int)) для кормить кодировщик необработанными данными. Это кажется легко, правда? Это не так, поскольку видеокодеры, к которым вы получаете доступ с помощью этого API, используют разные цветовые форматы, и вам необходимо поддерживать их все. Список этих цветовых форматов доступен здесь. Более того, многие кодировщики заявляют о поддержке цветовых форматов, которые на самом деле не поддерживаются должным образом или могут вызывать небольшие сбои.
Весь пакет hw посвящен решению этих проблем. См., в частности, класс EncoderDebugger .
Если потоковая передача с помощью этого API завершается неудачей, libstreaming переходит к потоковой передаче с помощью API MediaRecorder .
Метод поверхность-буфер использует метод createInputSurface(). Этот метод, вероятно, является лучшим способом кодирования необработанного видео с камеры, но для него требуется Android 4.3 и более поздние версии.
Пакет gl предназначен для использования API MediaCodec с поверхностью.
Он еще не включен по умолчанию в libstreaming, но вы можете принудительно включить его с помощью метода setStreamingMethod(byte) .
После кодирования необработанных данных от периферийных устройств они инкапсулируются в соответствующий поток RTP. Алгоритм пакетирования, который необходимо использовать, зависит от формата данных (H.264, H.263, AMR и AAC) и все они указаны в соответствующих RFC:
Если вы ищете базовую реализацию одного из упомянутых выше RFC, проверьте источники соответствующего класса.
Пакеты RTCP также отправляются получателю, начиная с версии 2.0 libstreaming. Реализованы только отчеты об отправителях. На самом деле они нужны для синхронизации губ.
Пакет 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 требует действительную поверхность для записи видео (это раздражающее ограничение API MediaRecorder ). В Android 4.3 потоковая передача без SurfaceView возможна, но еще не реализована. Вызов setContext(Context) необходим, он позволяет объектам H264Stream и объектам AACStream хранить и восстанавливать данные с помощью SharedPreferences .
Объект Session представляет собой сеанс потоковой передачи для некоторого узла. Он содержит один или несколько объектов Stream , которые запускаются (соответственно останавливаются) при вызове метода start() (соответственно stop() ).
Метод getSessionDescription() вернет SDP сеанса в виде строки. Перед его вызовом необходимо убедиться, что Сессия настроена. После вызова метода 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 ();
Посмотрите эту страницу вики и пример 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 сохраняет свои входные данные как строку, и его нельзя легко (потребуется переопределить) настроить для хранения его как целого числа.
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, чтобы узнать, как можно использовать этот стек потоковой передачи и как он работает.