libstreaming عبارة عن واجهة برمجة تطبيقات تسمح لك، باستخدام بضعة أسطر من التعليمات البرمجية، ببث الكاميرا و/أو الميكروفون الخاص بجهاز يعمل بنظام Android باستخدام RTP عبر UDP.
الخطوة الأولى التي ستحتاج إلى تحقيقها لبدء جلسة البث لبعض الأقران تسمى "الإشارة". خلال هذه الخطوة سوف تقوم بالاتصال بالمستلم وإرسال وصف للتدفقات الواردة. لديك ثلاث طرق للقيام بذلك باستخدام libstreaming.
تتوفر وثائق javadoc الكاملة لواجهة برمجة التطبيقات هنا: http://guigui.us/libstreaming/doc
هناك ثلاث طرق على Android للحصول على البيانات المشفرة من الأجهزة الطرفية:
لم تكن واجهة برمجة تطبيقات MediaRecorder مخصصة لتطبيقات البث ولكن يمكن استخدامها لاسترداد البيانات المشفرة من الأجهزة الطرفية للهاتف. الحيلة هي تكوين مثيل MediaRecorder للكتابة إلى LocalSocket بدلاً من ملف عادي (راجع MediaStream.java ).
تحرير: اعتبارًا من Android Lollipop، لم يعد استخدام LocalSocket ممكنًا لأسباب أمنية. لكن استخدام ParcelFileDescriptor يفي بالغرض. مزيد من التفاصيل في ملف MediaStream.java ! (شكرا لهؤلاء الرجال على البصيرة)
هذا الاختراق له بعض القيود:
من الصعب معرفة مدى نجاح هذا الاختراق على الهاتف. بالرغم من ذلك، فهو يعمل بشكل جيد على العديد من الأجهزة.
لا تقدم واجهة برمجة تطبيقات MediaCodec القيود التي ذكرتها للتو، ولكن لديها مشكلاتها الخاصة. توجد في الواقع طريقتان لاستخدام MediaCodec API: مع المخازن المؤقتة أو مع السطح.
تستخدم طريقة المخزن المؤقت إلى المخزن المؤقت استدعاءات dequeueInputBuffer و[ queueInputBuffer ](http://developer.android.com/reference/android/media/MediaCodec.html#queueInputBuffer(int, int, int, long, int)) إلى تغذية التشفير بالبيانات الأولية. يبدو ذلك سهلاً أليس كذلك؟ حسنًا، الأمر ليس كذلك، لأن برامج تشفير الفيديو التي يمكنك الوصول إليها باستخدام واجهة برمجة التطبيقات هذه تستخدم تنسيقات ألوان مختلفة وتحتاج إلى دعمها جميعًا. قائمة تنسيقات الألوان هذه متاحة هنا. علاوة على ذلك، تدعي العديد من برامج التشفير دعم تنسيقات الألوان التي لا تدعمها فعليًا بشكل صحيح أو يمكنها تقديم بعض الأخطاء البسيطة.
كل حزمة hw مخصصة لحل هذه المشكلات. انظر على وجه الخصوص فئة EncoderDebugger .
إذا فشل البث باستخدام واجهة برمجة التطبيقات (API) هذه، فسيتم إجراء عمليات احتياطية للبث باستخدام واجهة برمجة تطبيقات MediaRecorder .
تستخدم طريقة السطح إلى المخزن المؤقت طريقة createInputSurface(). ربما تكون هذه الطريقة هي أفضل طريقة لتشفير الفيديو الخام من الكاميرا ولكنها تتطلب نظام التشغيل Android 4.3 والإصدارات الأحدث.
حزمة gl مخصصة لاستخدام MediaCodec API مع السطح.
لم يتم تمكينه افتراضيًا بعد في 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 ببساطة إنشاء كائنات الجلسة . هناك حاجة إلى استدعاء setSurfaceView لدفق الفيديو، ولا ينبغي أن يكون ذلك بمثابة مفاجأة نظرًا لأن Android يتطلب سطحًا صالحًا لتسجيل الفيديو (وهو قيد مزعج لـ MediaRecorder API). في نظام التشغيل Android 4.3، يكون البث بدون SurfaceView ممكنًا ولكن لم يتم تنفيذه بعد. يعد استدعاء setContext(Context) ضروريًا، فهو يسمح لكائنات H264Stream وكائنات AACStream بتخزين البيانات واستعادتها باستخدام SharedPreferences .
يمثل كائن الجلسة جلسة بث لبعض الأقران. يحتوي على واحد أو أكثر من كائنات الدفق التي يتم تشغيلها (resp.stop) عند استدعاء طريقة start() (resp.stop () ).
ستعيد الطريقة getSessionDescription () SDP للجلسة في شكل سلسلة. قبل الاتصال بها، يجب عليك التأكد من تكوين الجلسة . بعد استدعاء config() أو startPreview() على مثيل الجلسة لديك، سيتم استدعاء رد الاتصال onSessionConfigured() .
في المثال الموضح أعلاه، يتم استخدام نسخة الجلسة بطريقة غير متزامنة ولا يتم حظر استدعاءات أساليبها. أنت تعرف متى تنتهي الأمور عندما يتم استدعاء عمليات الاسترجاعات.
يمكنك أيضًا استخدام كائن الجلسة بطريقة متزامنة مثل هذا:
// 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 ));
تفضل بزيارة صفحة جيثب هذه لترى كيف يمكن استخدام مكدس البث هذا وكيفية أدائه.