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,你會得到「偏移錯誤」。錄製是可能的,但播放受到限制。