问题描述
我正在尝试示例,以便使用
I am trying to fallow Truiton ScreenCapture example, in order to record the device screen using MediaProjection
保存记录时,它可以正常工作
When saving the recording localy it works
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时,它不是
How ever when changing to work with FileDescriptor it's not
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()
If not using the LocalServerSocket, then mMediaRecorder.prepare()
throw exception, now that I am using it, get exception in the below method in 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
作为eccpected。当我打电话给 mMediaRecorder.start()
This is my Java server, I get socket after mMediaRecorder.prepare()
is called and it stuck on inputStream.read
as eccpected. The exception in Android happands when I call 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,下面是我的部分工作,我有一个扩展MediaRecorder的MediaStreamer类。
You have to use LocalServerSocket, below is what partially worked for me, I have a MediaStreamer class which extends 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不是实时,可流式格式,因此即使通过套接字捕获数据,通常在音频或视频捕获结束时写入的关键文件头也会丢失(因为套接字不可见本地文件) - 因此无法播放的数据(因此,为什么它在保存为本地文件时工作正常,是可以理解的)。
But the main problem is mp4 is not very easy to stream . The basic problem is that MP4 is not live, streamable format, so even though data is captured via the socket, the crucial file headers which are normally written at the conclusion of an audio or video capture, are missing (because sockets are not seekeable like local files) - hence the unplayable data (And so, why it works fine when saved as local files, is understandable).
没有简单的方法来执行post-处理数据以手动添加文件头。所以解决方案是要么不使用MP4作为录制格式,要么编写类似于项目
There is no easy way to perform post-processing on the data to manually add the file headers. So the solution is either don't use MP4 as the recording format, or, write a packetiser similar to what is used in the Spydroid project
希望这会有所帮助!
这篇关于流Android屏幕的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!