pengantar

Nex Gen Media Server paling dikenal sebagai server streaming media multi-tujuan untuk mengirimkan video langsung dan disimpan ke berbagai perangkat. Server media yang sama dapat disematkan ke dalam aplikasi seluler untuk memfasilitasi komunikasi video waktu nyata. Di sini kita akan menggunakan NGMS API untuk memfasilitasi pembuatan klien obrolan video untuk perangkat Android menggunakan Android Software Developer Kit (SDK) dan Google Android Native Developer Kit (NDK).

Kami akan menggunakan NGMS untuk menyediakan semua layanan RTP transport jaringan, kompresi bingkai video dan dekompresi. NGMS akan berjalan sebagai objek bersama yang dikompilasi secara native yang digunakan oleh aplikasi Android kita. Kita akan menggunakan lapisan penghubung Java Native Interface (JNI) untuk memanggil metode asli dari kode aplikasi Java.

Prasyarat

Artikel ini mengasumsikan bahwa Anda memiliki pemahaman dasar dan setidaknya memiliki pengalaman tingkat menengah dalam membuat aplikasi Android. Saya tidak akan membahas detail pengaturan dan proyek Android di iDE seperti Eclipse. Jika sebelumnya Anda pernah membuat aplikasi Android, atau setidaknya mengikuti beberapa contoh tutorial, Anda harus dapat memanfaatkan tutorial ini untuk membuat klien streaming video waktu nyata.

Jika Anda belum melakukannya, Anda perlu mengunduh Google Android SDK (Software Developer Kit). Dalam contoh ini saya menggunakan Revisi 15 pada mesin 32bit Linux. Lapisan aplikasi java digunakan untuk membuat aplikasi Android yang sebenarnya. Kode aplikasi akan berinteraksi dengan lapisan JNI untuk menjalankan rutinitas API NGMS.

Anda juga perlu mengunduh Google Android NDK (Native Developer Kit). Dalam contoh ini saya menggunakan Revisi 6b pada mesin 32bit Linux. NDK akan digunakan untuk membuat lapisan antarmuka native yang berfungsi sebagai perekat antara kode native dan kode aplikasi Java. Anda juga harus memiliki pemahaman dasar tentang bahasa pemrograman C.

Pertama-tama Anda harus memulai dengan membuat aplikasi kerangka Android menggunakan IDE seperti Eclipse. Dalam contoh ini, aplikasi akan dipanggil ngmsclient. Nama paket Java akan disebut com.example.ngmsclient dan akan menargetkan Android OS 2.3 atau lebih tinggi. Direktori root project harus berisi folder bernama “jni” yang akan berisi sumber asli yang digunakan untuk berinteraksi dengan kode aplikasi Java. Contoh di bawah ini mengasumsikan bahwa Anda memiliki aplikasi kerangka Android yang berfungsi dan akan menunjukkan cara mengintegrasikan kelas ExampleChat ke dalam proyek Android Anda.

Lapisan Asli

Pustaka tertanam inti NGMS ditulis dalam C dan dikemas sebagai file objek bersama. Karena OS Android didasarkan pada Linux, pustaka inti NGMS akan berjalan secara native dalam ruang aplikasi Android Anda. Anda perlu mendapatkan pustaka inti NGMS untuk OS Android dari situs web ngmsvid.com. Komponen penting adalah file perpustakaan libngms.so, libxcode.so, dan file header ngmslib.h. File ngms bundled.so akan dikemas bersama dengan ngmsclient.apk Anda untuk menyediakan layanan obrolan video.

Lapisan JNI

Kita akan membangun pustaka bersama yang disebut ngmsglue.so yang akan berfungsi sebagai perekat antara ngms API dan kode aplikasi Java kita. Struktur direktori Java Native Interface (JNI) dalam direktori proyek ngmsclient Anda akan terlihat seperti ini.


jni/Android.mk
jni/ngmsglue.c
jni/ngms/include/ngmslib.h
jni/ngms/lib/libngms.so
jni/ngms/lib/libxcode.so

ngmsglue.c akan berisi kode untuk mengontrol keluaran NGMS dan fitur masukan. Kode tersebut akan mempertahankan dua konteks API NGMS yang terpisah, satu untuk parameter keluaran aliran dan satu lagi untuk parameter masukan aliran. Anda harus memperhatikan bahwa konvensi penamaan setiap fungsi harus cocok dengan paket Java dan nama kelas tempat Anda memanggil kode native.

ngmsStartReceiver dipanggil untuk menginisialisasi API masukan penangkapan NGMS untuk mendengarkan pada port 5004 untuk aliran video jaringan yang dienkapsulasi melalui MPEG-2 TS. Setiap bingkai video yang berurutan akan secara otomatis didemux dan diterjemahkan ke dalam format RGB565 piksel. Bingkai lengkap selanjutnya bisa dibaca dengan memanggil ngmsReceiveFrame.

ngmsStartSender dipanggil untuk menginisialisasi API keluaran aliran NGMS untuk mengeluarkan bingkai video yang dikodekan ke host jarak jauh melalui port 5004. ngmsTransmitFrame dipanggil untuk menyandikan dan mengirimkan satu bingkai mentah dalam format NV21 piksel.


/*
* ngmsglue.c
*
* JNI layer to access the NGMS streaming and capture API
*
*/

#include
#include
#include
#include
#include "ngmslib.h"

/**
* Holds the configuration for the NGMS RTP receiver and decoder
*/
static NGMSLIB_STREAM_PARAMS_T ngmsReceiver;

/**
* Holds the configuration for the NGMS RTP sender and encoder
*/
static NGMSLIB_STREAM_PARAMS_T ngmsSender;

/**
* Starts the NGMS capture service
*/
jint Java_com_example_ngmsclient_ExampleChat_ngmsStartReceiver (JNIEnv* _env, jobject _thiz)
{

char xcoderConfig[512];
char sdpConfig[512];
int i;

/*
* Before doing anything call ngmslib_open to open the NGMS service
*/
i = ngmslib_open(&ngmsReceiver);
if (i!= NGMS_RC_OK)
{
__android_log_print(ANDROID_LOG_ERROR, "ngms", "ngmslib_open failed with error %d", i);
return -1;
}

/*
* Construct an xcoder configuration key value string
*/
sprintf(xcoderConfig, "vc=rgb565,vx=320,vy=240");

/*
* Construct an SDP configuration for the RTP receiver
* Here we setup NGMS to read data over a MPEG-2 Transport Stream.
*/
sprintf(sdpConfig, "sdp://"
"m=video 5004 RTP/AVP 33n"
"a=rtpmap:33 MP2T/90000n"
"a=fmtp:33n");

/*
* Customize the capture configuration parameters
*/
ngmsReceiver.inputs[0] = sdpConfig;
ngmsReceiver.strxcode = xcoderConfig;
ngmsReceiver.islive = 1;
ngmsReceiver.noaud = 1;

/*
* Start the RTP receiver
*/
i = ngmslib_stream(&ngmsReceiver);

if (i!= NGMS_RC_OK)
{
__android_log_print(ANDROID_LOG_ERROR, "ngms", "ngmslib_stream failed with error %d", i);
ngmslib_close(&ngmsReceiver);
return -1;
}

return 0;
}

/**
* Stops the NGMS RTP capture service
*/
jint Java_com_example_ngmsclient_ExampleChat_ngmsStopReceiver (JNIEnv* _env, jobject _thiz)
{

/*
* Stop the RTP receiver
*/
ngmslib_close(&ngmsReceiver);

return 0;
}

/**
* NGMS Callback operation which blocks until a complete video frame has been received and decoded
*/
jint Java_com_example_ngmsclient_ExampleChat_ngmsReceiveFrame (JNIEnv* _env, jobject _thiz, jbyteArray frameBytes)
{
jstring str;

jboolean copy;
jbyte* buffer = (*_env)->GetByteArrayElements(_env, frameBytes, ©);
jsize max = (*_env)->GetArrayLength(_env, frameBytes);
int frameSize;

frameSize = ngmslib_readVidFrame(&ngmsReceiver, buffer, max, NULL);

(*_env)->ReleaseByteArrayElements(_env, frameBytes, buffer, JNI_ABORT);

return frameSize;

}

/**
* Starts the NGMS streaming service
*/
jint Java_com_example_ngmsclient_ExampleChat_ngmsStartSender (JNIEnv* _env, jobject _thiz, jstring remoteAddress)
{

char xcoderConfig[512];
char filter[512];
char destination[512];
const char *p;
int i;

/*
* Before doing anything call ngmslib_open to open the NGMS service
*/
i = ngmslib_open(&ngmsSender);

if (i!= NGMS_RC_OK)
{
__android_log_print(ANDROID_LOG_ERROR, "ngms", "ngmslib_open failed with error %d", i);
return -1;
}

/*
* Get the destination host string
*/
p = (*_env)->GetStringUTFChars(_env, remoteAddress, 0);

sprintf(destination, "rtp://%s:5004", p);

(*_env)->ReleaseStringUTFChars(_env, remoteAddress, p);

/*
* Customize the stream configuration parameters
*/
ngmsSender.output = destination;
sprintf(xcoderConfig, "vc=h264,vp=66,vb=250,vx=320,vy=240,vgmax=2000,vgmin=1500,vfr=15,vcfrout=-1,vth=1,vl=1,vsc=1,vf=2");
ngmsSender.strxcode = xcoderConfig;
sprintf(filter, "type=yuv420sp, ngmsSender.strfilters[0] = filter;
ngmsSender.inputs[0]= "/dev/dummyvideo";
ngmsSender.noaud = 1;

/*
* Start the RTP sender
*/
i = ngmslib_stream(&ngmsSender);

if (i!= NGMS_RC_OK)
{
__android_log_print(ANDROID_LOG_ERROR, "ngms", "ngmslib_stream failed with error %d", i);
ngmslib_close(&ngmsSender);
return -1;
}

return 0;
}

/**
* Stops the NGMS streaming service
*/
jint Java_com_example_ngmsclient_ExampleChat_ngmsStopSender (JNIEnv* _env, jobject _thiz)
{

/*
* Stop the RTP sender
*/
ngmslib_close(&ngmsSender);

return 0;
}

/**
* Encodes and transmits a single video frame using local RTP transport
*/
jint Java_com_example_ngmsclient_ExampleChat_ngmsTransmitFrame (JNIEnv* _env, jobject _thiz, jbyteArray frameBytes)
{

jboolean copy;
jbyte* buffer = (*_env)->GetByteArrayElements(_env, frameBytes, ©);
jsize size = (*_env)->GetArrayLength(_env, frameBytes);
int i;

i = ngmslib_onVidFrame(&ngmsSender, buffer, size);

(*_env)->ReleaseByteArrayElements(_env, frameBytes, buffer, JNI_ABORT);

return i;
}

Kami akan membuat makefile Android.mk yang digunakan oleh Android NDK untuk membuat pustaka ngmsglue kami.


#Example Android.mk Makefile

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE:= ngmsglue
LOCAL_SRC_FILES:= ngmsglue.c
LOCAL_C_INCLUDES:= ngms/include
LOCAL_LDFLAGS:= -Lngms/lib
LOCAL_LDLIBS:= -llog -lm -lngms -lxcode

include $(BUILD_SHARED_LIBRARY)

Untuk membuat pustaka bersama ngmsglue.so, cukup lakukan hal berikut.


cd [YOUR NGMSCLIENT PROJECT DIR]/jni
${ANDROID_NDK_HOME}/ndk-build

Ini harus menghasilkan file keluaran [YOUR NGMSCLIENT PROJECT DIR]/libs/armeabi/ibngmsglue.so

Anda mungkin perlu menyalin pustaka ngms / lib / libngms.so dan ngms / lib / libxcode.so secara manual ke dalam direktori keluaran libs / armeabi karena konten direktori ini akan secara otomatis dikemas ke dalam aplikasi project.apk.

Lapisan Aplikasi Java

Lapisan aplikasi java terdiri dari logika level aplikasi untuk aplikasi Android yang sedang kita buat. Untuk dapat menggunakan kode asli dari bagian sebelumnya kita perlu membuat aplikasi sederhana menggunakan Android SDK. Contoh ini menunjukkan penggunaan kelas ExampleChat yang dapat digunakan oleh aplikasi Anda sendiri untuk menyediakan streaming video interaktif waktu nyata. Itu tidak menunjukkan semua langkah yang diperlukan untuk membuat aplikasi streaming video Android lengkap. Pengembang Android tingkat menengah harus dapat menyelesaikan tugas dengan membangun dan menyertakan kelas ExampleChat dalam aplikasi lengkapnya.

Kelas ExampleChat yang ditunjukkan di bawah ini digunakan untuk mengontrol pengirim aliran NGMS dan penerima aliran NGMS. Metode startSender dapat dipanggil untuk memulai streaming video dari kamera asli menggunakan mekanisme pratinjau kamera. Setiap keluaran bingkai video oleh kamera diturunkan ke NGMS API di mana ia akan dikodekan dan dikirim ke pihak jarak jauh menggunakan enkapsulasi RTP asli. Metode starReceiver bisa dipanggil untuk mulai menerima video dari instance jarak jauh dari aplikasi yang sama. startReceiver meluncurkan utas yang melakukan polling pemblokiran untuk bingkai video yang diterima dan didekodekan berikutnya yang tersedia. Bersama-sama, kedua metode ini dapat digunakan untuk membuat streaming video dua arah antara dua instance jarak jauh dari aplikasi yang sama di seluruh jaringan.


/*
* ExampleChat.java
*
*/

package com.example.ngmsclient;

import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PreviewCallback;
import android.graphics.ImageFormat;

public class ExampleChat
{
private boolean myReceiverRunning;
private Camera myCamera;
private PreviewCallback myCameraCallback;

/**
* Change this value to the destination where the video will be streamed
*/
private static final DESTINATION = "10.0.0.1";

/**
* method to initialize and start sending video from the local camera
*/
public void startSender () throws Exception
{

myCamera = Camera.open();

Parameters parameters = myCamera.getParameters();
parameters.setPreviewFormat(ImageFormat.NV21);
parameters.setPreviewFrameRate(15);
parameters.setPreviewSize(320, 240);

myCamera.setParameters(parameters);

/**
* Call the NGMS native method to perform streaming initialization
*/
ngmsStartSender(DESTINATION);

myCameraCallback = new PreviewCallback()
{
public void onPreviewFrame(byte[] frameBytes, Camera camera)
{
/**
* Call the NGMS native routine to encode and transmit the video frame
* to the remote destination using RTP transport.
*/
ngmsTransmitFrame(frameBytes);
}
}

myCamera.startPreview();
myCamera.setPreviewCallback(myCameraCallback);

}

/**
* method to stop sending video
*/
public void stopSender () throws Exception
{
ngmsStopSender();
}

/**
* method to start receiving remote video
*/
public void startReceiver () throws Exception
{

/**
* Call the NGMS native method to perform input initialization
*/
ngmsStartReceiver();

/**
* Start the thread which will poll for received video frames
*/
new Thread(myVideoFrameReceiver).start();

}

/**
* method to stop receiving remote video
*/
public void stopReceiver () throws Exception
{
myReceiverRunning = false;
ngmsStopReceiver();
}

/**
* Thread used to check for decoded video frames
* received by the NGMS native layer
*/
private Runnable myVideoFrameReceiver = new Runnable()
{
public void run()
{
/**
* Allocate a buffer to hold a video frame 320 x 240 pixels
* in RGB565 format, taking 16 bits (2 bytes) per pixel.
*/
byte[] frameBytes = new byte[ 320 * 240 * 2 ];
int size;
myReceiverRunning = true;

while(myReceiverRunning)
{
/**
* Block until a frame has been received and decoded by the native layer
*/
size = ngmsReceiveFrame(frameBytes);
if(size > 0)
{
/**
* The frameBytes array represents a video frame in RGB565 format.
* These bytes can be converted into a Bitmap object for display
* on the screen.
*/
}
}
}
}

/**
* Static initialization to load native libraries into address space
*/
static
{
System.loadLibrary("xcode");
System.loadLibrary("ngms");
System.loadLibrary("ngmsglue");

}

/**
* Define native method prototypes
*/
public native int ngmsStartReceiver ();
public native int ngmsStopReceiver ();
public native int ngmsReceiveFrame (byte[] frameBytes);

public native int ngmsStartSender (String remoteAddress);
public native int ngmsStopSender ();
public native int ngmsTransmitFrame (byte[] frameBytes);

}

Setelah Anda mengintegrasikan kelas ExampleChat ke dalam proyek Android Anda sendiri, pastikan ketiga pustaka asli ada di direktori proyek / libs sehingga mereka akan dimasukkan ke dalam keluaran your.apk.


libs/armeabi/libngms.so
libs/armeabi/libxcode.so
libs/armeabi/libngmsglue.so

Contoh ini menghasilkan keluaran video ke alamat IP tujuan 10.0.0.1. Agar berhasil mengaktifkan dua klien untuk melakukan streaming video dua arah, Anda perlu mengubah alamat IP ini agar sesuai dengan klien jarak jauh Anda.

Kesimpulan

Contoh di atas menunjukkan cara melakukan streaming video langsung dari objek kamera secara real-time dan cara menerima streaming langsung jarak jauh serta mengekstrak setiap bingkai video yang telah diterjemahkan untuk ditampilkan. Alur proses yang sama dapat diterapkan untuk menambahkan streaming audio untuk membuat aplikasi obrolan video lengkap. â € ¨

Untuk melihat Panduan API Tertanam Server Media Nex Gen (NGMS), buka http://ngmsvid.com/develop.php



Source by Hung B Nguyen