13

Próbuję odłogiem Truiton ScreenCapture przykład, aby nagrać ekran urządzenia za pomocą MediaProjectionStream android ekran

Podczas zapisywania nagranie lokalnie działa

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(); 

Jak zawsze przy zmianie pracy z deskryptora pliku to nie

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(); 

Jeśli nie używając LocalServerSocket, to wyjątek mMediaRecorder.prepare() rzut teraz, że jestem z nami ing go uzyskać wyjątek w poniższej metody w 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*/); 
} 

wyjątkiem

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)  

To jest mój serwer Java, mam gniazdo po mMediaRecorder.prepare() nazywa i naklejane na inputStream.read jak eccpected. Wyjątkiem w Android happands gdy zgłoszę 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(); 
    } 

Odpowiedz

7

Musisz użyć LocalServerSocket, poniżej jest co częściowo pracował dla mnie, mam MediaStreamer klasę, która rozciąga 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; 
     } 
    } 
} 

Do nagrywania

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(); 


Ale głównym problemem jest to, mp4 nie jest bardzo łatwy do strumienia. Podstawowym problemem jest to, że MP4 nie jest formatem live i streamowalnym, więc nawet jeśli dane są przechwytywane przez gniazdo, brakuje kluczowych nagłówków plików, które normalnie są zapisane na zakończenie przechwytywania audio lub wideo (ponieważ gniazda nie są dostępne do wyszukiwania, pliki lokalne) - stąd dane nie do odtworzenia (dlaczego więc działa poprawnie po zapisaniu jako pliki lokalne, jest zrozumiałe).

Nie ma łatwego sposobu wykonywania przetwarzania końcowego danych, aby ręcznie dodać nagłówki plików. Rozwiązaniem jest albo nie używać MP4 jako formatu zapisu, albo napisać pakiet podobny do tego, który jest używany w projekcie .

+0

Czy moja odpowiedź jest niewystarczająca lub wymagane są dodatkowe wyjaśnienia, plz daj mi znać? –

+0

Jak znaleźć "Twój_socket_addr" w nodejs - architektura easyRTC? –