23

我是新来的Android编程和发现自己被困我一直在研究各种方式从手机传输实时视频电话,似乎有它主要的功能,除了当然的了最重要的部分:播放流。它似乎是从一部手机发送流,但第二部手机无法播放流。流实时视频电话使用套接字fd

这里是打边

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

的代码,这里是流侧

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 
    } 
} 

我试图创建的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) 
时收到以下错误代码

没有人对此有一个解决?提前致谢!

+0

你得到它的工作? – B770 2013-08-19 09:36:56

+0

是为你工作吗?如果它正在工作,请告诉我如何解决这个问题。 – Aravi 2013-12-10 08:18:19

+0

关于这个问题有几个问题,都以同样的方式结束,有人说它应该是可能的,但没有真正的答案,没有工作代码的例子,它非常令人沮丧。 – steveh 2014-07-06 01:06:28

回答

6

我发现一个开源项目实现了我的努力。它通过IP摄像头通过元数据处理视频。虽然它不直接将视频发送到手机,但它可以播放各种设备观看的视频。源代码可在以下项目页面http://code.google.com/p/ipcamera-for-android/中找到。

在Android 4.4系统还有另一种方式来播放实时MJPEG流。您正在播放的流应通过UDP端口上的其他设备进行广播。假设我们有一个流在192.168.0.101:8080上广播。我们可以通过在我们的布局中添加WebView来播放流。然后在我们的活动中,我们执行以下操作:

@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); 
} 

在内容中,我们告诉网页使用设备的dpi。为了支持用户缩放网页,我添加了以下initial-scale = 1,minimum-scale = 1,user-scalable = yes。最初,图像是原始尺寸,不能变小。用户现在可以缩放以放大图像并缩小为原始大小。删除最小比例尺将使用户完全控制缩放,但可能导致图像变得很小,以致无法找到它。

+1

无法运行此项目。你能写出它的步骤吗? – 2013-12-02 10:50:38

+0

所以你最终不使用MediaPlayer。 – lifelogger 2014-04-06 16:24:32

0

看看Streaming to the Android MediaPlayer,这可能对如何做流一些有用的技巧。我怀疑问题在于Android试图在文件中寻找,但是作为网络套接字 - 它不能。也许某种支持寻找的磁盘/内存缓冲可能有帮助?

+0

它看起来好像我将不得不按照建议做一些缓冲区。我会在早上尝试一下,看看会发生什么。感谢这篇文章。 – 2011-05-25 04:10:32

+0

它看起来像流媒体文件没有适合mediaplayer播放的格式。我不知道如何解决这个问题。 – 2011-05-25 15:57:00

+1

媒体播放器遇到流媒体问题的一种方式是如果元数据未先发送。通常情况下,您可以使用像ffmpeg的qt-faststart这样的工具将元数据放在内容之前,但我不确定在旅途中生成流时如何执行此操作。 – 2011-05-25 16:57:45

3

您必须设置录像机输出格式8(MPEG-2TS,只能从android版本3.0+获得)。 在这种情况下,记录以这种格式的视频和流发送给其他手机,并将其保存在一个文件中。并在文件中写入一些数据后播放它,然后您可以看到直播流。

注 - 无法直接播放套接字文件描述符,因为套接字fd不可查找。如果你使用socket fd,你会得到“偏移错误”。录制是可能的,但播放受到限制。