web-dev-qa-db-fra.com

Diffusez des vidéos en direct d'un téléphone à un autre à l'aide de la prise fd

Je suis nouveau dans la programmation Android et je me suis retrouvé coincé. J'ai recherché différentes façons de diffuser des vidéos en direct d'un téléphone à un autre et semble l'avoir principalement fonctionnel, sauf bien sûr la partie la plus importante: lecture du flux. Il semble envoyer le flux à partir d'un téléphone, mais le deuxième téléphone ne peut pas lire le flux.

Voici le code pour le côté de jeu

public class VideoPlayback extends Activity implements Callback {
MediaPlayer mp;
private SurfaceView mPreview;
private SurfaceHolder holder;
private TextView mTextview;
public static final int SERVERPORT = 6775;
public static String SERVERIP="192.168.1.126";
Socket clientSocket;
private Handler handler = new Handler();
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    mPreview = (SurfaceView) findViewById(R.id.surfaceView1);
    mTextview = (TextView) findViewById(R.id.textView1);
    holder = mPreview.getHolder();
    holder.addCallback(this);
    holder.setType(SurfaceHolder.SURFACE_TYPE_Push_BUFFERS);
    mTextview.setText("Attempting to connect");
    mp = new MediaPlayer();
    Thread t = new Thread(){
        public void run(){
            try {
                    clientSocket = new Socket(SERVERIP,SERVERPORT);
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        mTextview.setText("Connected to server");
                    }
                });
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(clientSocket);
                            pfd.getFileDescriptor().sync();
                            mp.setDataSource(pfd.getFileDescriptor());
                            pfd.close();
                            mp.setDisplay(holder);
                            mp.prepareAsync();
                            mp.start();
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }

                    }
                });

            } catch (UnknownHostException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    };
    t.start();
}

Et voici le code pour le côté streaming

public class VideoStreaming extends Activity{
// User Interface Elements
VideoView mView;
TextView connectionStatus;
SurfaceHolder mHolder;
// Video variable
MediaRecorder recorder; 
// Networking variables
public static String SERVERIP="";
public static final int SERVERPORT = 6775;
private Handler handler = new Handler();
private ServerSocket serverSocket;  
/** Called when the activity is first created. */
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    // Define UI elements
    mView = (VideoView) findViewById(R.id.video_preview);
    connectionStatus = (TextView) findViewById(R.id.connection_status_textview);
    mHolder = mView.getHolder();
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_Push_BUFFERS);
    SERVERIP = "192.168.1.126";
    // Run new thread to handle socket communications
    Thread sendVideo = new Thread(new SendVideoThread());
    sendVideo.start();
}
 public class SendVideoThread implements Runnable{
    public void run(){
        // From Server.Java
        try {
            if(SERVERIP!=null){
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        connectionStatus.setText("Listening on IP: " + SERVERIP);
                    }
                });
                serverSocket = new ServerSocket(SERVERPORT);
                while(true) {
                    //listen for incoming clients
                    Socket client = serverSocket.accept();
                    handler.post(new Runnable(){
                        @Override
                        public void run(){
                            connectionStatus.setText("Connected.");
                        }
                    });
                    try{
                            // Begin video communication
                            final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(client);
                            handler.post(new Runnable(){
                                @Override
                                public void run(){
                                    recorder = new MediaRecorder();
                                    recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
                                    recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);                 
                                    recorder.setOutputFile(pfd.getFileDescriptor());
                                    recorder.setVideoFrameRate(20);
                                    recorder.setVideoSize(176,144);
                                    recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
                                    recorder.setPreviewDisplay(mHolder.getSurface());
                                    try {
                                        recorder.prepare();
                                    } catch (IllegalStateException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                    } catch (IOException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                    }
                                    recorder.start();
                                }
                            });
                    } catch (Exception e) {
                        handler.post(new Runnable(){
                            @Override
                            public void run(){
                                connectionStatus.setText("Oops.Connection interrupted. Please reconnect your phones.");
                            }
                        });
                        e.printStackTrace();
                    }
                }
            } else {
                handler.post(new Runnable() {
                    @Override
                    public void run(){
                        connectionStatus.setText("Couldn't detect internet connection.");
                    }
                });
            }
        } catch (Exception e){
            handler.post(new Runnable() {
                @Override
                public void run() {
                    connectionStatus.setText("Error");
                }
            });
            e.printStackTrace();
        }
        // End from server.Java
    }
}

Je reçois l'erreur suivante lors de la tentative de création de MediaPLayer

05-24 16:25:39.360: ERROR/MediaPlayerService(88): offset error
05-24 16:25:39.360: ERROR/MediaPlayer(11895): Unable to to create media player
05-24 16:25:39.360: WARN/System.err(11895): Java.io.IOException: setDataSourceFD failed.: status=0x80000000
05-24 16:25:39.360: WARN/System.err(11895):     at Android.media.MediaPlayer.setDataSource(Native Method)
05-24 16:25:39.360: WARN/System.err(11895):     at Android.media.MediaPlayer.setDataSource(MediaPlayer.Java:811)
05-24 16:25:39.360: WARN/System.err(11895):     at com.conti.VideoPlayBack.VideoPlayback$1$2.run(VideoPlayback.Java:63)
05-24 16:25:39.360: WARN/System.err(11895):     at Android.os.Handler.handleCallback(Handler.Java:587)
05-24 16:25:39.360: WARN/System.err(11895):     at Android.os.Handler.dispatchMessage(Handler.Java:92)
05-24 16:25:39.360: WARN/System.err(11895):     at Android.os.Looper.loop(Looper.Java:132)
05-24 16:25:39.360: WARN/System.err(11895):     at Android.app.ActivityThread.main(ActivityThread.Java:4025)
05-24 16:25:39.360: WARN/System.err(11895):     at Java.lang.reflect.Method.invokeNative(Native Method)
05-24 16:25:39.360: WARN/System.err(11895):     at Java.lang.reflect.Method.invoke(Method.Java:491)
05-24 16:25:39.360: WARN/System.err(11895):     at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:841)
05-24 16:25:39.360: WARN/System.err(11895):     at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:599)
05-24 16:25:39.360: WARN/System.err(11895):     at dalvik.system.NativeStart.main(Native Method)

Quelqu'un a-t-il une solution pour cela? Merci d'avance!

24
udm_coder

J'ai trouvé un projet open source pour implémenter ce que j'essayais. Il traite la vidéo avec des métadonnées via une caméra IP. Bien qu'il n'envoie pas de vidéo directement à un téléphone, il diffuse de la vidéo pour différents appareils à regarder. Le code source peut être trouvé sur la page de projet suivante http://code.google.com/p/ipcamera-for-Android/ .

Avec Android 4.4, il existe une autre façon de lire un flux MJPEG en direct. Le flux que vous lisez doit être diffusé par l'autre appareil sur un port via UDP. Disons que nous avons un flux diffusé sur 192.168.0.101:8080. Nous pouvons lire le flux en ajoutant une WebView à notre mise en page. Ensuite, dans notre activité, nous procédons comme suit:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.mjpeg_activity);
    // Grab instance of WebView
    WebView webView = (WebView)findViewById(R.id.webViewStream);
    // Set page content for webview
    webView.loadData("<html><head><meta name='viewport' content='target-densitydpi=device-dpi,initial-scale=1,minimum-scale=1,user-scalable=yes'/></head><body><center><img src=\"http://192.168.0.101:8080/\" alt=\"Stream\" align=\"middle\"></center></body></html>", "text/html", null);
    webView.getSettings().setBuiltInZoomControls(true);
}

Dans le contenu, nous indiquons à la page Web d'utiliser le dpi de l'appareil. Pour aider l'utilisateur à pincer le zoom sur la page Web, j'ai ajouté l'échelle initiale suivante = 1, l'échelle minimale = 1, l'échelle utilisateur = oui. Initialement, l'image a sa taille d'origine et ne peut pas devenir plus petite. L'utilisateur peut maintenant redimensionner pour zoomer sur l'image et revenir à sa taille d'origine. La suppression de l'échelle minimale donnera à l'utilisateur un contrôle complet sur le zoom, mais peut rendre l'image si petite que vous ne la trouverez pas.

6
udm_coder

Vous devez définir le format de sortie de l'enregistreur 8 (MPEG-2TS, uniquement disponible à partir de Android version 3.0+). Dans ce cas, enregistrez la vidéo dans ce format et envoyez le flux vers un autre téléphone et enregistrez-le dans un fichier. Et lisez-le après avoir écrit des données dans le fichier, puis vous pourrez voir le flux en direct.

Remarque - Vous ne pouvez pas lire directement le descripteur de fichier socket, car le socket fd n'est pas recherché. Si vous utilisez le socket fd, vous obtiendrez une "erreur de décalage". L'enregistrement est possible, mais la lecture est limitée.

4
Suvam Roy

Télécharger le code source depuis: http://code.google.com/p/ipcamera-for-Android/ ( https://github.com/Teaonly/Android-eye =)

Construisez d'abord le jni (utilisez ndk-build avec cygwin)

J'ai pu construire ce projet avec succès

0
Phuong

Jetez un œil à Streaming vers le Android MediaPlayer , qui peut avoir quelques conseils utiles sur la façon de faire le streaming. Je soupçonne que le problème est qu'Android essaie de chercher le fichier, mais étant un socket réseau - il ne peut pas. Peut-être qu'une sorte de tampon disque/mémoire qui prend en charge la recherche pourrait aider?

0
Steve Pomeroy