NDK开发汇总
public class VideoChannel implements Camera.PreviewCallback, CameraHelper.OnChangedSizeListener {
private LivePusher mLivePusher;
private CameraHelper cameraHelper;
private int mBitrate;
private int mFps;
private boolean isLiving;
public VideoChannel(LivePusher livePusher, Activity activity, int width, int height, int bitrate, int fps, int cameraId) {
mLivePusher = livePusher;
mBitrate = bitrate;
mFps = fps;
cameraHelper = new CameraHelper(activity, cameraId, width, height);
//1、让camerahelper的
cameraHelper.setPreviewCallback(this);
//2、回调 真实的摄像头数据宽、高
cameraHelper.setOnChangedSizeListener(this);
}
public void setPreviewDisplay(SurfaceHolder surfaceHolder) {
cameraHelper.setPreviewDisplay(surfaceHolder);
}
/**
* 得到nv21数据 已经旋转好的
*
* @param data
* @param camera
*/
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
if (isLiving) {
mLivePusher.native_pushVideo(data);
}
}
public void switchCamera() {
cameraHelper.switchCamera();
}
/**
* 真实摄像头数据的宽、高
* @param w
* @param h
*/
@Override
public void onChanged(int w, int h) {
//初始化编码器
mLivePusher.native_setVideoEncInfo(w, h, mFps, mBitrate);
}
public void startLive() {
isLiving = true;
}
public void stopLive() {
isLiving = false;
}
}
保留音频接口
public class AudioChannel {
public void stopLive() {
}
public void startLive() {
}
}
public class CameraHelper implements SurfaceHolder.Callback, Camera.PreviewCallback {
private static final String TAG = "CameraHelper";
private Activity mActivity;
private int mHeight;
private int mWidth;
private int mCameraId;
private Camera mCamera;
private byte[] buffer;
private SurfaceHolder mSurfaceHolder;
private Camera.PreviewCallback mPreviewCallback;
private int mRotation;
private OnChangedSizeListener mOnChangedSizeListener;
public CameraHelper(Activity activity, int cameraId, int width, int height) {
mActivity = activity;
mCameraId = cameraId;
mWidth = width;
mHeight = height;
}
public void switchCamera() {
if (mCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
mCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
} else {
mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
stopPreview();
startPreview();
}
private void stopPreview() {
if (mCamera != null) {
//预览数据回调接口
mCamera.setPreviewCallback(null);
//停止预览
mCamera.stopPreview();
//释放摄像头
mCamera.release();
mCamera = null;
}
}
private void startPreview() {
try {
//获得camera对象
mCamera = Camera.open(mCameraId);
//配置camera的属性
Camera.Parameters parameters = mCamera.getParameters();
//设置预览数据格式为nv21
parameters.setPreviewFormat(ImageFormat.NV21);
//这是摄像头宽、高
setPreviewSize(parameters);
// 设置摄像头 图像传感器的角度、方向
setPreviewOrientation(parameters);
mCamera.setParameters(parameters);
buffer = new byte[mWidth * mHeight * 3 / 2];
//数据缓存区
mCamera.addCallbackBuffer(buffer);
mCamera.setPreviewCallbackWithBuffer(this);
//设置预览画面
mCamera.setPreviewDisplay(mSurfaceHolder);
mOnChangedSizeListener.onChanged(mWidth, mHeight);
mCamera.startPreview();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void setPreviewOrientation(Camera.Parameters parameters) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(mCameraId, info);
mRotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (mRotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90: // 横屏 左边是头部(home键在右边)
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:// 横屏 头部在右边
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
//设置角度
mCamera.setDisplayOrientation(result);
}
private void setPreviewSize(Camera.Parameters parameters) {
//获取摄像头支持的宽、高
List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();
Camera.Size size = supportedPreviewSizes.get(0);
Log.d(TAG, "支持 " + size.width + "x" + size.height);
//选择一个与设置的差距最小的支持分辨率
// 10x10 20x20 30x30
// 12x12
int m = Math.abs(size.height * size.width - mWidth * mHeight);
supportedPreviewSizes.remove(0);
Iterator<Camera.Size> iterator = supportedPreviewSizes.iterator();
//遍历
while (iterator.hasNext()) {
Camera.Size next = iterator.next();
Log.d(TAG, "支持 " + next.width + "x" + next.height);
int n = Math.abs(next.height * next.width - mWidth * mHeight);
if (n < m) {
m = n;
size = next;
}
}
mWidth = size.width;
mHeight = size.height;
parameters.setPreviewSize(mWidth, mHeight);
Log.d(TAG, "设置预览分辨率 width:" + size.width + " height:" + size.height);
}
public void setPreviewDisplay(SurfaceHolder surfaceHolder) {
mSurfaceHolder = surfaceHolder;
mSurfaceHolder.addCallback(this);
}
public void setPreviewCallback(Camera.PreviewCallback previewCallback) {
mPreviewCallback = previewCallback;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//释放摄像头
stopPreview();
//开启摄像头
startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
stopPreview();
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
// data数据依然是倒的
mPreviewCallback.onPreviewFrame(data, camera);
camera.addCallbackBuffer(buffer);
}
public void setOnChangedSizeListener(OnChangedSizeListener listener) {
mOnChangedSizeListener = listener;
}
public interface OnChangedSizeListener {
void onChanged(int w, int h);
}
}
public class LivePusher {
static {
System.loadLibrary("native-lib");
}
private AudioChannel audioChannel;
private VideoChannel videoChannel;
public LivePusher(Activity activity, int width, int height, int bitrate,
int fps, int cameraId) {
native_init();
videoChannel = new VideoChannel(this, activity, width, height, bitrate, fps, cameraId);
audioChannel = new AudioChannel();
}
public void setPreviewDisplay(SurfaceHolder surfaceHolder) {
videoChannel.setPreviewDisplay(surfaceHolder);
}
public void switchCamera() {
videoChannel.switchCamera();
}
public void startLive(String path) {
native_start(path);
videoChannel.startLive();
audioChannel.startLive();
}
public void stopLive() {
videoChannel.stopLive();
audioChannel.stopLive();
native_stop();
}
public native void native_init();
public native void native_start(String path);
public native void native_setVideoEncInfo(int width, int height, int fps, int bitrate);
public native void native_pushVideo(byte[] data);
public native void native_stop();
public native void native_release();
}
public class PlayActivity extends AppCompatActivity {
private LivePusher livePusher;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play);
getPermission();
SurfaceView surfaceView = findViewById(R.id.surfaceView);
livePusher = new LivePusher(this, 800, 480, 800_000, 10, Camera.CameraInfo.CAMERA_FACING_BACK);
// 设置摄像头预览的界面
livePusher.setPreviewDisplay(surfaceView.getHolder());
}
public void switchCamera(View view) {
livePusher.switchCamera();
}
public void startLive(View view) {
livePusher.startLive("rtmp://47.94.164.223/myapp/abc");
}
public void stopLive(View view) {
livePusher.stopLive();
}
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.INTERNET,
Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO
};
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private void getPermission() {
ActivityCompat.requestPermissions(this,
PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
}
}
RTMPDump