一. 服务器端MainActivity
public class MainActivity extends AppCompatActivity {
private MediaProjectionManager mediaProjectionManager;
private SocketLive socketLive;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkPermission();
mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
Intent captureIntent = mediaProjectionManager.createScreenCaptureIntent();
startActivityForResult(captureIntent, 1);
}
public boolean checkPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
}, 1);
}
return false;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK || requestCode != 1) return;
MediaProjection mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
if (mediaProjection == null) {
return;
}
socketLive = new SocketLive(12000);
socketLive.start(mediaProjection);
}
@Override
protected void onDestroy() {
super.onDestroy();
socketLive.close();
}
}
二. 服务器端SocketLive
public class SocketLive {
private static final String TAG = "liuyi";
private WebSocket webSocket;
int port;
CodecLiveH265 codecLiveH265;
public SocketLive(int port) {
this.port = port;
}
public void start(MediaProjection mediaProjection) {
webSocketServer.start();
codecLiveH265 = new CodecLiveH265(this,mediaProjection);
codecLiveH265.startLive();
}
public void close() {
try {
webSocket.close();
webSocketServer.stop();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void sendData(byte[] bytes) {
if (webSocket != null && webSocket.isOpen()) {
webSocket.send(bytes);
}
}
private WebSocketServer webSocketServer = new WebSocketServer(new InetSocketAddress(12003)) {
@Override
public void onOpen(WebSocket webSocket, ClientHandshake handshake) {
SocketLive.this.webSocket = webSocket;
}
@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
}
@Override
public void onMessage(WebSocket conn, String message) {
}
@Override
public void onError(WebSocket conn, Exception ex) {
}
@Override
public void onStart() {
}
};
}
三. 服务器端CodecLiveH265
public class CodecLiveH265 extends Thread{
private MediaCodec mediaCodec;
private int width = 720;
private int height = 1280;
private MediaProjection mediaProjection;
VirtualDisplay virtualDisplay;
private SocketLive socketLive;
public CodecLiveH265(SocketLive socketLive, MediaProjection mediaProjection) {
this.mediaProjection = mediaProjection;
this.socketLive = socketLive;
}
public void startLive() {
try {
MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_HEVC, width, height);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
format.setInteger(KEY_BIT_RATE, width * height);
format.setInteger(KEY_FRAME_RATE, 20);
format.setInteger(KEY_I_FRAME_INTERVAL, 1);
mediaCodec = MediaCodec.createEncoderByType("video/hevc");
mediaCodec.configure(format,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE);
Surface surface=mediaCodec.createInputSurface();
//创建场地
virtualDisplay = mediaProjection.createVirtualDisplay(
"-display",
width, height, 1,
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, surface, null, null);
start();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
mediaCodec.start();
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
while (true) {
try {
int outputBufferId = mediaCodec.dequeueOutputBuffer(bufferInfo, 10000);
if (outputBufferId >= 0) {
//编码好的H265的数据
ByteBuffer byteBuffer=mediaCodec.getOutputBuffer(outputBufferId);
// byte[] outData = new byte[bufferInfo.size];
// byteBuffer.get(outData);
// writeContent(outData); //以字符串的方式写入
dealFrame(byteBuffer ,bufferInfo);
mediaCodec.releaseOutputBuffer(outputBufferId, false);
}
} catch (Exception e) {
e.printStackTrace();
break;
}
}
}
public static final int NAL_I = 19;
public static final int NAL_VPS = 32;
private byte[] vps_sps_pps_buf;
private void dealFrame(ByteBuffer bb, MediaCodec.BufferInfo bufferInfo) {
int offset = 4;
if (bb.get(2) == 0x01) {
offset = 3;
}
int type = (bb.get(offset) &0x7E)>>1;
if (type==NAL_VPS) {
vps_sps_pps_buf = new byte[bufferInfo.size];
bb.get(vps_sps_pps_buf);
} else if (type == NAL_I) {
final byte[] bytes = new byte[bufferInfo.size];
bb.get(bytes);
byte[] newBuf = new byte[vps_sps_pps_buf.length + bytes.length];
System.arraycopy(vps_sps_pps_buf, 0, newBuf, 0, vps_sps_pps_buf.length);
System.arraycopy(bytes, 0, newBuf, vps_sps_pps_buf.length, bytes.length);
this.socketLive.sendData(newBuf);
} else {
final byte[] bytes = new byte[bufferInfo.size];
bb.get(bytes);
this.socketLive.sendData(bytes);
}
}
}
四. 客户端MainActivity
public class MainActivity extends AppCompatActivity implements SocketLive.SocketCallback {
private static final String TAG = "liuyi";
private Surface surface ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceView1);
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
surface = holder.getSurface();
initSocket();
initDecoder(surface);
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
}
});
}
private void initSocket() {
SocketLive screenLive = new SocketLive(this,12000);
screenLive.start();
}
MediaCodec mediaCodec;
public void initDecoder(Surface surface) {
try {
mediaCodec = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_VIDEO_HEVC);
final MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_HEVC, 720, 1280);
format.setInteger(MediaFormat.KEY_BIT_RATE, 720 * 1280);
format.setInteger(MediaFormat.KEY_FRAME_RATE, 20);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
mediaCodec.configure(format, surface, null, 0);
mediaCodec.start();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void callBack(byte[] data) {
int index = mediaCodec.dequeueInputBuffer(100000);
if (index >= 0) {
ByteBuffer inputBuffer = mediaCodec.getInputBuffer(index);
inputBuffer.clear();
inputBuffer.put(data, 0, data.length);
mediaCodec.queueInputBuffer(index, 0, data.length, System.currentTimeMillis(), 0);
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 100000);
while (outputBufferIndex > 0) {
mediaCodec.releaseOutputBuffer(outputBufferIndex, true );
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
}
}
五. 客户端SocketLive
public class SocketLive {
private static final String TAG = "SocketLive";
private SocketCallback socketCallback;
MyWebSocketClient myWebSocketClient;
private WebSocket webSocket;
private int port;
public SocketLive(SocketCallback socketCallback, int port) {
this.socketCallback = socketCallback;
this.port = port;
}
public void start() {
try {
URI url = new URI("ws://192.168.1.169:12003");
myWebSocketClient = new MyWebSocketClient(url);
myWebSocketClient.connect();
} catch (Exception e) {
e.printStackTrace();
}
}
private class MyWebSocketClient extends WebSocketClient {
public MyWebSocketClient(URI serverURI) {
super(serverURI);
}
@Override
public void onOpen(ServerHandshake handshakedata) {
Log.i(TAG, "打开 socket onOpen: ");
}
@Override
public void onMessage(String message) {
}
@Override
public void onMessage(ByteBuffer bytes) {
Log.i(TAG, "消息长度 : "+bytes.remaining());
byte[] buf = new byte[bytes.remaining()];
bytes.get(buf);
socketCallback.callBack(buf);
}
@Override
public void onClose(int code, String reason, boolean remote) {
}
@Override
public void onError(Exception ex) {
}
}
public interface SocketCallback{
void callBack(byte[] data);
}
}
网友评论