Подтвердить что ты не робот

Стрим-андроид

Я пытаюсь использовать 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() throw exception, теперь, когда я его использую, получите исключение в методе ниже в 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, как и ожидалось. Исключение в Android происходит, когда я звоню 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();
    }
4b9b3361

Ответ 1

Вы должны использовать 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 проект

Надеюсь, это поможет!