最近公司需求搞視訊監控視訊對講,但個人對視訊這塊基本全無了解。在網上翻了一圈之後,使用EasyDarwin家的源碼做了基礎嘗試。
EasyCamera
首先是移植EasyCamera。既然要移植,當然要分析源碼。

EasyCamera的主要UI在StreamActivity上,如果是隻是想抓一個視訊界面來用,隻要把這個Activity搬過去就好。不過我的需求是在我自己的項目的界面上進行顯示。是以還要拆分啊。
UI方面的暫且不提。
mMediaStream = new MediaStream(getApplicationContext(), surfaceView.getHolder());
mMediaStream.updateResolution(width, height);
mMediaStream.setDgree(getDgree());
以上是初始化一個流媒體
接下來我們看一下它的構造。
public MediaStream(Context context, SurfaceHolder holder) {
mApplicationContext = context;
mSurfaceHolderRef = new WeakReference(holder);
mEasyPusher = new EasyPusher();
audioStream = new AudioStream(mEasyPusher, null, EasyApplication.aio, EasyApplication.sMainBus);
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "kim onReceive: "+intent.getAction());
mRequestSnapshot = true;
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(MediaStream.ACTION_SNAPSHOT_REQ);
LocalBroadcastManager.getInstance(mApplicationContext).registerReceiver(mReceiver, filter);
}
其中EasyPusher是直接對接jni方法。對于jni我也全無研究,今後要适當看點資料了。
而AudioStream内提供了一個編碼方法。
回到StreamActivity,再看下一步:
mPusherCallBack = new EasyPusher.OnInitPusherCallback() {
@Override
public void onCallback(int code) {
switch (code) {
case CODE.EASY_ACTIVATE_INVALID_KEY:
sendMessage("無效Key");
break;
case CODE.EASY_ACTIVATE_SUCCESS:
sendMessage("激活成功");
break;
case CODE.EASY_PUSH_STATE_CONNECTING:
sendMessage("連接配接中");
這個功能是什麼就不用多說了吧。
之後注冊的一個廣播也是核心功能。
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (CommandService.ACTION_START_STREAM.equals(intent.getAction())) {
} else if (CommandService.ACTION_STOP_STREAM.equals(intent.getAction())) {
} else if (CommandService.ACTION_COMMOND_RESTART_THREAD.equals(intent.getAction())) {
}
};
其中ACTION_START_STREAM内便是開始啟動視訊對接。具體内容請去看源碼。
我需要的功能也很簡單,就是移植。是以把初始化内的内容照原樣搬過去就可以了。不過在搬過去的途中遇到了一個小坑,主要來自于移植所用的SurfaceView
<SurfaceView
android:id="@+id/sv_surfaceview"
android:keepScreenOn="true"
android:layout_width="match_parent"
android:layout_height="match_parent" />
這個SurfaceView在android測試中似乎必須顯示,移出視圖外也不行,若不顯示則在某些機子上會出現對面的Client可以聽見聲音,但是無法觀看視訊的現象。具體原因是什麼我也不知道,如果有知道的大牛希望可以不吝賜教。
EasyClient中的清單與EasyCamera配對的方式主要是通過Serial,是以如果有需求對指定使用者名進行比對的情況,就把這句修改就好了。
public String getDeviceSerial(){
return InfoSharedPreference.getString(this , Config.device_serial_key);
}
EasyCilent
下一步是移植EasyClient。
移植EasyClient的途中沒遇上太多坑,還算是比較順利的。公司需求是點選使用者的監視按鈕,則對已開啟EasyCamera的使用者進行監視。
EasyClient中我主要使用的就是
EasyPlayerActivity這個activity。原樣搬過去基本就可以了,當然途中若修改了包名,則需要去官方申請一個key值。
- 注意申請時填寫的必須是ApplicationID而不是包名。
key替換在這裡。
private void startRending(Surface surface) {
mStreamRender = new EasyRTSPClient(this, "79393674363536526D3432413254315A7073496D4A655A76636D63755A57467A65575268636E64706269356C59584E35593278705A573530567778576F502B6C34456468646D6C754A6B4A68596D397A595541794D4445325257467A65555268636E6470626C526C5957316C59584E35", surface, mResultReceiver);
Log.i("SpeedTalk" , "Url>>>" + mRTSPUrl + ",TCP>>" + RTSPClient.TRANSTYPE_TCP);
mStreamRender.start(mRTSPUrl, RTSPClient.TRANSTYPE_TCP, RTSPClient.EASY_SDK_VIDEO_FRAME_FLAG | RTSPClient.EASY_SDK_AUDIO_FRAME_FLAG, "admin", "admin");
}
在點選打開這個Activity之前,還需要對已開啟EasyCamera的使用者進行一個查詢。
查詢的代碼在CameraFragment中,首頁的三個碎片都是繼承自這個界面的,隻需要替換
protected String mType = "ARM_Linux";
就可以進行切換。
MyApplication.asyncGet(url, new CallbackWrapper<DeviceListBody>(DeviceListBody.class) {
@Override
public void onBefore(Request request) {
mSwipeRefreshLayout.setRefreshing(false);
activity.showWaitProgress("");
}
@Override
public void onAfter() {
activity.hideWaitProgress();
}
@Override
public void onError(Call call, Exception e) {
Toast.makeText(mContext, "onError:" + e.toString(), Toast.LENGTH_LONG).show();
}
@Override
public void onResponse(DeviceListBody body) {
List<DeviceListBody.Device> devices = body.getDevices();
if (devices.size() == ) {
activity.showToadMessage("暫無直播資訊");
liveVOAdapter = new OnlineCameraAdapter(new ArrayList<DeviceListBody.Device>());
} else {
liveVOAdapter = new OnlineCameraAdapter(devices);
int screenW = mContext.getResources().getDisplayMetrics().widthPixels;
int columnum = mGrid_live.getNumColumns();
int space = (int) (mContext.getResources().getDimension(R.dimen.gridview_horizontalspacing));
int itemWidth = (int) ((screenW - (columnum - ) * space) / columnum);
int itemHeight = getItemHeight(itemWidth);
liveVOAdapter.setmSnapshotWidth(itemWidth);
liveVOAdapter.setmSnapshotHeight(itemHeight);
// int screenW = mContext.getResources().getDisplayMetrics().widthPixels;
// int columnum = mGrid_live.getNumColumns();
// int space = (int)(mContext.getResources().getDimension(R.dimen.gridview_horizontalspacing));
// int itemWidth = (int)((screenW-(columnum-1)*space)/columnum);
// int itemHeight = (int) (itemWidth * 4 / 3.0 + 0.5f);
// liveVOAdapter.setmSnapshotWidth(itemWidth);
// liveVOAdapter.setmSnapshotHeight(itemHeight);
}
mGrid_live.setAdapter(liveVOAdapter);
}
});
上面的onResponse就是進行了直播清單查詢的相關方法。在使用時隻需要原樣替換就好。
移植兩邊之後,就可以進行正常的監視操作了。至于實作對講,還在繼續研究。至少這個案例當兩邊同時監聽的時候,Android端會崩潰。
EasyDarwin這個平台稍微有點不穩定,後續需要調整的部分估計有不少。
上個官網源碼。
https://github.com/EasyDarwin