开始编写基于zego的直播模块
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
package com.mogo.cloud.live;
|
||||
|
||||
/**
|
||||
* YUV数据回调
|
||||
*/
|
||||
public interface IYUVDataCallback {
|
||||
void onFrame(byte[] data);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.mogo.cloud.live;
|
||||
package com.mogo.cloud.live.listener;
|
||||
|
||||
/**
|
||||
* 直播状态回调用
|
||||
*/
|
||||
public interface ILiveStatusCallback {
|
||||
public interface ILiveStatusListener {
|
||||
void onChange(String camId, int status);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.mogo.cloud.live.listener;
|
||||
|
||||
/**
|
||||
* YUV数据回调
|
||||
*/
|
||||
public interface IYUVDataListener {
|
||||
void onFrame(byte[] data);
|
||||
}
|
||||
@@ -1,37 +1,42 @@
|
||||
package com.mogo.cloud.live.utils;
|
||||
package com.mogo.cloud.live.manager;
|
||||
|
||||
|
||||
import com.mogo.cloud.live.IYUVDataCallback;
|
||||
import com.mogo.cloud.live.listener.IYUVDataListener;
|
||||
import com.zhidao.libyuv.Key;
|
||||
import com.zhidao.libyuv.YuvUtils;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class FrameManagerUtils {
|
||||
/**
|
||||
* 视频帧管理
|
||||
*/
|
||||
public class CameraFrameManager {
|
||||
private static final int DST_WIDTH = 1280;
|
||||
private static final int DST_HEIGHT = 720;
|
||||
|
||||
byte[] dst = null;
|
||||
byte[] tmp = null;
|
||||
|
||||
private final Set<IYUVDataCallback> globalDataListener = new HashSet<>();
|
||||
private final Set<IYUVDataListener> globalDataListener = new HashSet<>();
|
||||
|
||||
public static FrameManagerUtils getInstance() {
|
||||
public static CameraFrameManager getInstance() {
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
private static final class SingletonHolder {
|
||||
private static final FrameManagerUtils INSTANCE = new FrameManagerUtils();
|
||||
private static final CameraFrameManager INSTANCE = new CameraFrameManager();
|
||||
}
|
||||
|
||||
public void notifyYUVData(byte[] data, int width, int height, int type) {
|
||||
dispatchData(handleData(data, width, height, type));
|
||||
}
|
||||
|
||||
/*
|
||||
* @param data origin yuv data
|
||||
* @param width data width
|
||||
/**
|
||||
* @param data origin yuv data
|
||||
* @param width data width
|
||||
* @param height data height
|
||||
* @param type 1:YV12 2:NV21 3:I420 4 nv12
|
||||
* @param type 1:YV12 2:NV21 3:I420 4 nv12
|
||||
*/
|
||||
private byte[] handleData(byte[] data, int width, int height, int type) {
|
||||
if (dst == null) {
|
||||
@@ -80,13 +85,13 @@ public class FrameManagerUtils {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
public synchronized void addYuvDataCallback(IYUVDataCallback callback) {
|
||||
public synchronized void addYuvDataCallback(IYUVDataListener callback) {
|
||||
if (callback != null) {
|
||||
globalDataListener.add(callback);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void rmYuvDataCallback(IYUVDataCallback callback) {
|
||||
public synchronized void rmYuvDataCallback(IYUVDataListener callback) {
|
||||
if (callback != null) {
|
||||
globalDataListener.remove(callback);
|
||||
}
|
||||
@@ -99,7 +104,7 @@ public class FrameManagerUtils {
|
||||
|
||||
private void dispatchData(byte[] data) {
|
||||
if (globalDataListener != null && globalDataListener.size() > 0) {
|
||||
for (IYUVDataCallback callback : globalDataListener) {
|
||||
for (IYUVDataListener callback : globalDataListener) {
|
||||
if (callback != null) {
|
||||
callback.onFrame(data);
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import java.util.ArrayList;
|
||||
|
||||
import im.zego.zegoexpress.ZegoExpressEngine;
|
||||
import im.zego.zegoexpress.callback.IZegoCustomVideoCaptureHandler;
|
||||
import im.zego.zegoexpress.callback.IZegoDestroyCompletionCallback;
|
||||
import im.zego.zegoexpress.callback.IZegoEventHandler;
|
||||
import im.zego.zegoexpress.constants.ZegoEngineState;
|
||||
import im.zego.zegoexpress.constants.ZegoNetworkMode;
|
||||
@@ -63,15 +62,15 @@ public class ZeGoLiveManager {
|
||||
/**
|
||||
* 直播会议ID,使用推流端的车机信息建立房间ID,这里采用格式为:ROOM_ID_车机SN编号
|
||||
*/
|
||||
private static final String ROOM_ID_PREFIX = "ROOM_ID_";
|
||||
public static final String ROOM_ID_PREFIX = "ROOM_ID_";
|
||||
/**
|
||||
* 直播用户名称的
|
||||
*/
|
||||
private static final String NAME_PREFIX = "MoGoCar_";
|
||||
public static final String NAME_PREFIX = "MoGoCar_";
|
||||
/**
|
||||
* 直播流ID,发起推送的直播流ID
|
||||
*/
|
||||
private static final String STREAM_ID_PREFIX = "STREAM_ID_"; //+ "_" + System.currentTimeMillis()
|
||||
public static final String STREAM_ID_PREFIX = "STREAM_ID_"; //+ "_" + System.currentTimeMillis()
|
||||
/**
|
||||
* 定义 即构SDK 引擎对象
|
||||
*/
|
||||
@@ -160,6 +159,8 @@ public class ZeGoLiveManager {
|
||||
customVideoCaptureConfig = new ZegoCustomVideoCaptureConfig();
|
||||
// 设置自定义视频采集视频帧数据类型
|
||||
customVideoCaptureConfig.bufferType = ZegoVideoBufferType.RAW_DATA;
|
||||
// true 表示静音(关闭)
|
||||
mExpressEngine.muteMicrophone(true);
|
||||
// 开始或停止自定义视频采集,支持设置其他通道的推流
|
||||
mExpressEngine.enableCustomVideoCapture(true, customVideoCaptureConfig, ZegoPublishChannel.MAIN);
|
||||
// 设置自定义视频采集回调
|
||||
@@ -327,7 +328,7 @@ public class ZeGoLiveManager {
|
||||
* @param userId 当前用户ID
|
||||
* @param roomId 要进入的房间ID
|
||||
*/
|
||||
private void loginRoom(String userId, String roomId) {
|
||||
public void loginRoom(String userId, String roomId) {
|
||||
currentRoomId = ROOM_ID_PREFIX + roomId;
|
||||
ZegoUser zegoUser = new ZegoUser(userId, NAME_PREFIX + userId);
|
||||
mExpressEngine.loginRoom(currentRoomId, zegoUser);
|
||||
@@ -368,6 +369,7 @@ public class ZeGoLiveManager {
|
||||
*/
|
||||
public void stopLive(String streamId) {
|
||||
mExpressEngine.stopPlayingStream(streamId);
|
||||
stopPreview();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -418,7 +420,6 @@ public class ZeGoLiveManager {
|
||||
* 停止推送
|
||||
*/
|
||||
public void stopPublish() {
|
||||
stopPreview();
|
||||
stopPublishingStream();
|
||||
}
|
||||
|
||||
@@ -434,6 +435,7 @@ public class ZeGoLiveManager {
|
||||
* 停止观看直播
|
||||
*/
|
||||
public void onDestroyLive() {
|
||||
stopPreview();
|
||||
logOutRoom();
|
||||
destroyEngine();
|
||||
}
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
package com.mogo.cloud.live.push;
|
||||
package com.mogo.cloud.live.server;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioFormat;
|
||||
import android.os.IBinder;
|
||||
import android.text.TextUtils;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import com.mogo.cloud.live.IYUVDataCallback;
|
||||
import com.mogo.cloud.live.listener.IYUVDataListener;
|
||||
import com.mogo.cloud.live.manager.CameraFrameManager;
|
||||
import com.mogo.cloud.live.manager.MGLivePushConfig;
|
||||
import com.mogo.cloud.live.manager.ZeGoLiveManager;
|
||||
import com.mogo.cloud.live.utils.ByteUtils;
|
||||
|
||||
|
||||
public class PushService extends Service implements IYUVDataCallback {
|
||||
public class PushService extends Service implements IYUVDataListener {
|
||||
public static final String ACTION_START_RTMP_PUSH = "action_start_rtmp_push";
|
||||
public static final String ACTION_STOP_RTMP_PUSH = "action_stop_rtmp_push";
|
||||
|
||||
private static final String TAG = "PushService";
|
||||
|
||||
private static final String RTMP_URL = "rtmp_url";
|
||||
private static final String DEVICES_ID = "devices_id";
|
||||
private static final String CAM_ID = "cam_id";
|
||||
|
||||
private static final int WIDTH = 1280;
|
||||
@@ -29,12 +31,24 @@ public class PushService extends Service implements IYUVDataCallback {
|
||||
private MGLivePushConfig mLivePushConfig;
|
||||
private ZeGoLiveManager mLivePusher;
|
||||
|
||||
private static volatile String mRtmpUrl;
|
||||
/**
|
||||
* 当前设备ID,作为推流端,userID==roomId==streamID
|
||||
*/
|
||||
private volatile String mDevicesId;
|
||||
|
||||
public static void startService(Context context, String action, String rtmpurl, String camId) {
|
||||
/**
|
||||
* 启动服务
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param action 动作标志
|
||||
* @param devicesId 设备ID
|
||||
* @param camId 摄像头
|
||||
*/
|
||||
public static void startService(Context context, String action,
|
||||
String devicesId, String camId) {
|
||||
Intent intent = new Intent(context, PushService.class);
|
||||
intent.setAction(action);
|
||||
intent.putExtra(RTMP_URL, rtmpurl);
|
||||
intent.putExtra(DEVICES_ID, devicesId);
|
||||
intent.putExtra(CAM_ID, camId);
|
||||
context.startService(intent);
|
||||
}
|
||||
@@ -44,8 +58,8 @@ public class PushService extends Service implements IYUVDataCallback {
|
||||
super.onCreate();
|
||||
Log.d(TAG, "初始化推流服务……");
|
||||
mLivePushConfig = new MGLivePushConfig();
|
||||
mLivePushConfig.setWidth(1280);
|
||||
mLivePushConfig.setHeight(720);
|
||||
mLivePushConfig.setWidth(WIDTH);
|
||||
mLivePushConfig.setHeight(HEIGHT);
|
||||
mLivePushConfig.setVideoBitrate(1500);
|
||||
mLivePushConfig.setVideoFPS(15);
|
||||
mLivePushConfig.setAudioChannels(2);
|
||||
@@ -54,7 +68,7 @@ public class PushService extends Service implements IYUVDataCallback {
|
||||
mLivePushConfig.setMute(true);
|
||||
|
||||
mLivePusher = ZeGoLiveManager.getInstance();
|
||||
mLivePusher.init(getApplication(),mLivePushConfig);
|
||||
mLivePusher.init(getApplication(), mLivePushConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,13 +76,13 @@ public class PushService extends Service implements IYUVDataCallback {
|
||||
if (intent != null) {
|
||||
if (ACTION_START_RTMP_PUSH.equals(intent.getAction())) {
|
||||
try {
|
||||
String url = intent.getStringExtra(RTMP_URL);
|
||||
startRtmpPush(url);
|
||||
String devicesId = intent.getStringExtra(DEVICES_ID);
|
||||
startPush(devicesId);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else if (ACTION_STOP_RTMP_PUSH.equals(intent.getAction())) {
|
||||
stopRtmpPush();
|
||||
stopPush();
|
||||
}
|
||||
}
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
@@ -79,54 +93,39 @@ public class PushService extends Service implements IYUVDataCallback {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void startRtmpPush(String url) {
|
||||
if (mRtmpUrl != null && mRtmpUrl.equals(url)
|
||||
/**
|
||||
* 启动发布直播视频流
|
||||
*
|
||||
* @param devicesId 设备ID
|
||||
*/
|
||||
private void startPush(String devicesId) {
|
||||
if (mDevicesId != null && mDevicesId.equals(devicesId)
|
||||
&& mLivePusher != null && mLivePusher.isPushing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mRtmpUrl = url;
|
||||
|
||||
String rtmpUrl = null;
|
||||
if (!TextUtils.isEmpty(mRtmpUrl)) {
|
||||
String url1[] = mRtmpUrl.split("###");
|
||||
if (url1.length > 0) {
|
||||
rtmpUrl = url1[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(rtmpUrl) || (!rtmpUrl.trim().toLowerCase().startsWith("rtmp://"))) {
|
||||
//TODO rtmp url 地址有误
|
||||
Log.e(TAG, "rtmp url 地址有误");
|
||||
return;
|
||||
}
|
||||
|
||||
//int customModeType = 0;
|
||||
//customModeType |= TXLiveConstants.CUSTOM_MODE_VIDEO_CAPTURE;
|
||||
//mLivePusher.setVideoQuality(TXLiveConstants.VIDEO_QUALITY_HIGH_DEFINITION, true, true);
|
||||
//mLivePushConfig.setVideoResolution(TXLiveConstants.VIDEO_RESOLUTION_TYPE_1280_720);
|
||||
//mLivePushConfig.setAutoAdjustBitrate(false);
|
||||
//mLivePushConfig.setHomeOrientation(TXLiveConstants.VIDEO_ANGLE_HOME_LEFT);
|
||||
//mLivePushConfig.setVideoBitrate(900);
|
||||
//mLivePushConfig.setVideoEncodeGop(1);
|
||||
//mLivePushConfig.setVideoFPS(15);
|
||||
//mLivePushConfig.setCustomModeType(customModeType);
|
||||
|
||||
|
||||
FrameManagerUtils.getInstance().addYuvDataCallback(this);
|
||||
|
||||
mLivePusher.startPusher(rtmpUrl.trim());
|
||||
|
||||
Log.d(TAG, "startRtmpPush :" + rtmpUrl);
|
||||
mDevicesId = devicesId;
|
||||
// 注册视频YUV回调监听
|
||||
CameraFrameManager.getInstance().addYuvDataCallback(this);
|
||||
// 登录房间
|
||||
mLivePusher.loginRoom(mDevicesId, mDevicesId);
|
||||
// 开始发布
|
||||
mLivePusher.startPush(mDevicesId);
|
||||
Log.d(TAG, "startPush :mRoomId=" + mDevicesId + " mDevicesId=" + mDevicesId);
|
||||
}
|
||||
|
||||
private void stopRtmpPush() {
|
||||
/**
|
||||
* 结束发布直播视频流
|
||||
*/
|
||||
private void stopPush() {
|
||||
try {
|
||||
mRtmpUrl = "";
|
||||
mDevicesId = "";
|
||||
// 是否处于发布状态
|
||||
if (mLivePusher.isPushing()) {
|
||||
mLivePusher.stopPusher();
|
||||
// 停止发布
|
||||
mLivePusher.stopPublish();
|
||||
}
|
||||
FrameManagerUtils.getInstance().rmYuvDataCallback(this);
|
||||
// 移除视频回碉监听
|
||||
CameraFrameManager.getInstance().rmYuvDataCallback(this);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -135,8 +134,10 @@ public class PushService extends Service implements IYUVDataCallback {
|
||||
@Override
|
||||
public void onFrame(byte[] data) {
|
||||
if (mLivePusher != null && mLivePusher.isPushing() && data != null) {
|
||||
int ret = mLivePusher.sendCustomVideoData(data, 3, WIDTH, HEIGHT);
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "onFrame push ret is:" + ret);
|
||||
// 将YUV数据发布到即构
|
||||
ZeGoLiveManager.getInstance().startPublishingStream(
|
||||
ByteUtils.getBuffer(data, data.length), data.length,
|
||||
SystemClock.elapsedRealtime());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.mogo.cloud.live.utils;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class ByteUtils {
|
||||
|
||||
private static ByteBuffer byteBuffer;
|
||||
|
||||
public static ByteBuffer getBuffer(byte[] bytes, int length) {
|
||||
if (byteBuffer == null) {
|
||||
byteBuffer = ByteBuffer.allocateDirect(length);
|
||||
}
|
||||
byteBuffer.put(bytes);
|
||||
byteBuffer.flip();
|
||||
return byteBuffer;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user