我正在尝试使用Truiton ScreenCapture示例,以便使用MediaProjection记录设备屏幕
当保存录制本地时,它工作
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
String localFilePath = getLocalFilePath();
mMediaRecorder.setOutputFile(localFilePath);
mMediaRecorder.setVideoSize(DISPLAY_WIDTH, DISPLAY_HEIGHT);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.prepare();
如何改变工作与FileDescriptor不是
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
String hostname = "10.26.100.18";
int port = 2007;
Socket socket = new Socket(InetAddress.getByName(hostname), port);
ParcelFileDescriptor fileDescriptor = ParcelFileDescriptor.fromSocket(socket);
LocalServerSocket localServerSocket = new LocalServerSocket(fileDescriptor.getFileDescriptor());
mMediaRecorder.setOutputFile(localServerSocket.getFileDescriptor());
mMediaRecorder.setVideoSize(DISPLAY_WIDTH, DISPLAY_HEIGHT);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.prepare();
如果不使用LocalServerSocket,那么mMediaRecorder.prepare()
抛出异常,现在我正在使用它,在mMediaRecorder.getSurface()
中获得以下方法中的异常
private VirtualDisplay createVirtualDisplay() {
return mMediaProjection.createVirtualDisplay("MainActivity",
DISPLAY_WIDTH, DISPLAY_HEIGHT, mScreenDensity,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mMediaRecorder.getSurface(), null /*Callbacks*/, null
/*Handler*/);
}
异常
Caused by: java.lang.IllegalStateException: failed to get surface
at android.media.MediaRecorder.getSurface(Native Method)
at com.truiton.screencapture.MainActivity$override.createVirtualDisplay(MainActivity.java:172)
at com.truiton.screencapture.MainActivity$override.onActivityResult(MainActivity.java:133)
at com.truiton.screencapture.MainActivity$override.access$dispatch(MainActivity.java)
at com.truiton.screencapture.MainActivity.onActivityResult(MainActivity.java:0)
at android.app.Activity.dispatchActivityResult(Activity.java:6456)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3695)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3742)
at android.app.ActivityThread.-wrap16(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1393)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
这是我的Java服务器,我在mMediaRecorder.prepare()
被调用后得到套接字,并且它在inputStream.read
上卡住了。当我调用mMediaRecorder.start()
final byte[] buffer = new byte[1024];
try {
ServerSocket serverSocket = new ServerSocket(2007);
while (!serverSocket.isClosed()) {
Socket socket = serverSocket.accept();
File videoFile = createEmptyVideoFile();
FileOutputStream outputStream = new FileOutputStream(videoFile);
InputStream inputStream = socket.getInputStream();
int length = inputStream.read(buffer);
while (length != -1) {
outputStream.write(buffer, 0, length);
length = inputStream.read(buffer);
}
}
} catch (IOException e) {
e.printStackTrace();
}
你必须使用LocalServerSocket,下面是部分工作对我来说,我有一个MediaStreamer类扩展MediaRecorder。
public class MediaStreamer extends MediaRecorder {
private LocalServerSocket localServerSocket = null;
private LocalSocket receiver, sender = null;
public void prepare() throws IllegalStateException,IOException {
receiver = new LocalSocket();
try {
localServerSocket = new LocalServerSocket("<your_socket_addr>");
receiver.connect(new LocalSocketAddress("<your_socket_addr>"));
receiver.setReceiveBufferSize(4096);
receiver.setSendBufferSize(4096);
sender = localServerSocket.accept();
sender.setReceiveBufferSize(4096);
sender.setSendBufferSize(4096);
} catch (IOException e1) {
throw new IOException("Can't create local socket !");
}
setOutputFile(sender.getFileDescriptor());
try {
super.prepare();
} catch (Exception e) {
closeSockets();
throw e;
}
}
public InputStream getInputStream() {
InputStream out = null;
try {
out = receiver.getInputStream();
} catch (IOException e) {
}
return out;
}
public void stop() {
closeSockets();
super.stop();
}
private void closeSockets() {
if (localServerSocket !=null) {
try {
localServerSocket.close();
sender.close();
receiver.close();
}
catch (IOException e) {
}
localServerSocket = null;
sender = null;
receiver = null;
}
}
}
为记录video = new MediaStreamer();
video.reset();
video.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
video.setPreviewDisplay(holder.getSurface());
video.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
video.setVideoFrameRate(VideoConstants.frameRate);
video.setVideoEncodingBitRate(VideoConstants.bitRate*1000);
video.setVideoSize(VideoConstants.resolationX, VideoConstants.resolationY);
video.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
try {
video.prepare();
} catch (IOException e) {
e.printStackTrace();
}
video.start();
但主要的问题是mp4不是很容易流。基本的问题是MP4不是实时的,流媒体格式,所以即使数据是通过套接字捕获的,通常在音频或视频捕获结束时写入的关键文件头也丢失了(因为套接字不像本地文件那样可搜索)-因此无法播放的数据(所以,为什么它在保存为本地文件时工作良好,是可以理解的)。
没有简单的方法对数据进行后处理,手动添加文件头。因此,解决方案是要么不使用MP4作为录制格式,要么编写一个类似于Spydroid项目中使用的打包程序