2011-03-17 16 views
10

Estoy tratando de crear una aplicación de transmisión de video en vivo que transmita videos en vivo desde Android.Aplicación de transmisión de video en vivo en Android

Utilizando la clase MediaRecorder, puedo capturar los datos de video en forma de 3gp, con códecs h263.

Sin embargo, cuando ejecuto mi aplicación y transmite medios, recibo una demora de 2-3 segundos en el lado del servidor.

¿Por qué estoy recibiendo este retraso? ¿Hay algún búfer interno que deba enjuagar? ¿Hay otras formas de transmisión de video aparte de usar la clase MediaRecorder?

+0

¡Hola! También estoy tratando de lograr lo mismo. ¿Podría darme algunos detalles de cómo lo hizo con mediarecorder? –

+0

¿Podría proporcionarnos más detalles? ¿Qué biblioteca (ffmpeg, live555, etc. ...), qué enfoque (RTP, RTSP ...) usas? comment by flock.dux –

+0

hola Vladimir Ivanov .... ¿me pueden sugerir todo el proceso de transmisión de video en vivo en android ... no sé cómo comenzar con la transmisión de video en vivo ... vv gracias a ustedes por adelantado. ... esperando tu respuesta ... – shyam

Respuesta

-4

primero crea esta clase.

MediaPlayerDemo_Video.java:- 


package com.videostreaming.player; 

import android.app.Activity; 
import android.content.Intent; 
import android.media.AudioManager; 
import android.media.MediaPlayer; 
import android.media.MediaPlayer.OnBufferingUpdateListener; 
import android.media.MediaPlayer.OnCompletionListener; 
import android.media.MediaPlayer.OnPreparedListener; 
import android.media.MediaPlayer.OnVideoSizeChangedListener; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.SurfaceHolder; 
import android.view.SurfaceView; 
import android.widget.Toast; 


public class MediaPlayerDemo_Video extends Activity implements 
     OnBufferingUpdateListener, OnCompletionListener, 
     OnPreparedListener, OnVideoSizeChangedListener, SurfaceHolder.Callback { 

    private String path1 = "http://podcast.20min-tv.ch/podcast/20min/199733.mp4"; 
    // private String path2 = "http://podcast.20min-tv.ch/podcast/20min/199752.mp4"; 
    private String path2 = "http://podcast.20min-tv.ch/podcast/20min/199693.mp4"; 
    private String path = ""; 

    private static final String TAG = "MediaPlayerDemo"; 
    private int mVideoWidth; 
    private int mVideoHeight; 
    private MediaPlayer mMediaPlayer; 
    private SurfaceView mPreview; 
    private SurfaceHolder holder; 
// private String path; 
    private Bundle extras; 
    private static final String MEDIA = "media"; 
    private static final int LOCAL_AUDIO = 1; 
    private static final int STREAM_AUDIO = 2; 
    private static final int RESOURCES_AUDIO = 3; 
    private static final int LOCAL_VIDEO = 4; 
    private static final int STREAM_VIDEO = 5; 
    private boolean mIsVideoSizeKnown = false; 
    private boolean mIsVideoReadyToBePlayed = false; 

    private Bundle bdlReceivedData = null; 
    private Intent self = null; 

    /** 
    * 
    * Called when the activity is first created. 
    */ 
    @Override 
    public void onCreate(Bundle icicle) { 
     super.onCreate(icicle); 
     setContentView(R.layout.mediaplayer_2); 

     mPreview = (SurfaceView) findViewById(R.id.surface); 
     holder = mPreview.getHolder(); 
     holder.addCallback(this); 
     holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 

     extras = getIntent().getExtras(); 

     self = this.getIntent(); 
     bdlReceivedData = self.getExtras(); 

     if (bdlReceivedData != null && bdlReceivedData.getInt("video") > 0) 
     { 
      if (bdlReceivedData.getInt("video") == 1) 
      { 
       Toast.makeText(MediaPlayerDemo_Video.this,"playing Video 1", Toast.LENGTH_SHORT); 
       path = path1; 
      } 
      else if (bdlReceivedData.getInt("video") == 2) 
      { 
       Toast.makeText(MediaPlayerDemo_Video.this,"playing Video 2", Toast.LENGTH_SHORT); 
       path = path2; 
      } 
     } 
    } 

    private void playVideo(Integer Media) { 
     doCleanUp(); 
     try { 

//   switch (Media) { 
//    case LOCAL_VIDEO: 
//     /* 
//      * TODO: Set the path variable to a local media file path. 
//      */ 
//     path = ""; 
//     if (path == "") { 
//      // Tell the user to provide a media file URL. 
//      Toast 
//        .makeText(
//          MediaPlayerDemo_Video.this, 
//          "Please edit MediaPlayerDemo_Video Activity, " 
//            + "and set the path variable to your media file path." 
//            + " Your media file must be stored on sdcard.", 
//          Toast.LENGTH_LONG).show(); 
// 
//     } 
//     break; 
//    case STREAM_VIDEO: 
//     /* 
//      * TODO: Set path variable to progressive streamable mp4 or 
//      * 3gpp format URL. Http protocol should be used. 
//      * Mediaplayer can only play "progressive streamable 
//      * contents" which basically means: 1. the movie atom has to 
//      * precede all the media data atoms. 2. The clip has to be 
//      * reasonably interleaved. 
//      * 
//      */ 
//     path = ""; 
//     if (path == "") { 
//      // Tell the user to provide a media file URL. 
//      Toast 
//        .makeText(
//          MediaPlayerDemo_Video.this, 
//          "Please edit MediaPlayerDemo_Video Activity," 
//            + " and set the path variable to your media file URL.", 
//          Toast.LENGTH_LONG).show(); 
// 
//     } 
// 
//     break; 
// 
// 
//   } 

      // Create a new media player and set the listeners 
      mMediaPlayer = new MediaPlayer(); 
      mMediaPlayer.setDataSource(path); 
      mMediaPlayer.setDisplay(holder); 
      mMediaPlayer.prepare(); 
      mMediaPlayer.setOnBufferingUpdateListener(this); 
      mMediaPlayer.setOnCompletionListener(this); 
      mMediaPlayer.setOnPreparedListener(this); 
      mMediaPlayer.setOnVideoSizeChangedListener(this); 
      mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 

     } catch (Exception e) { 
      Log.e(TAG, "error: " + e.getMessage(), e); 
     } 
    } 

    public void onBufferingUpdate(MediaPlayer arg0, int percent) { 
     Log.d(TAG, "onBufferingUpdate percent:" + percent); 

    } 

    public void onCompletion(MediaPlayer arg0) { 
     Log.d(TAG, "onCompletion called"); 
    } 

    public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { 
     Log.v(TAG, "onVideoSizeChanged called"); 
     if (width == 0 || height == 0) { 
      Log.e(TAG, "invalid video width(" + width + ") or height(" + height + ")"); 
      return; 
     } 
     mIsVideoSizeKnown = true; 
     mVideoWidth = width; 
     mVideoHeight = height; 
     if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) { 
      startVideoPlayback(); 
     } 
    } 

    public void onPrepared(MediaPlayer mediaplayer) { 
     Log.d(TAG, "onPrepared called"); 
     mIsVideoReadyToBePlayed = true; 
     if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) { 
      startVideoPlayback(); 
     } 
    } 

    public void surfaceChanged(SurfaceHolder surfaceholder, int i, int j, int k) { 
     Log.d(TAG, "surfaceChanged called"); 

    } 

    public void surfaceDestroyed(SurfaceHolder surfaceholder) { 
     Log.d(TAG, "surfaceDestroyed called"); 
    } 


    public void surfaceCreated(SurfaceHolder holder) { 
     Log.d(TAG, "surfaceCreated called"); 
     playVideo(extras.getInt(MEDIA)); 
    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 
     releaseMediaPlayer(); 
     doCleanUp(); 
    } 

    @Override 
    protected void onDestroy() { 
     super.onDestroy(); 
     releaseMediaPlayer(); 
     doCleanUp(); 
    } 

    private void releaseMediaPlayer() { 
     if (mMediaPlayer != null) { 
      mMediaPlayer.release(); 
      mMediaPlayer = null; 
     } 
    } 

    private void doCleanUp() { 
     mVideoWidth = 0; 
     mVideoHeight = 0; 
     mIsVideoReadyToBePlayed = false; 
     mIsVideoSizeKnown = false; 
    } 

    private void startVideoPlayback() { 
     Log.v(TAG, "startVideoPlayback"); 
     holder.setFixedSize(mVideoWidth, mVideoHeight); 
     mMediaPlayer.start(); 
    } 
} 

ahora la siguiente clase

MainMenu.java 


package com.videostreaming.player; 

import android.app.Activity; 
import android.content.Intent; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.Button; 

public class MainMenu extends Activity { 

    Button btn_videoViewDemo1; 
    Button btn_videoViewDemo2; 
    Button btn_MediaPlayerDemo1;  
    Button btn_MediaPlayerDemo2; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     // TODO Auto-generated method stub 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     btn_videoViewDemo1 = (Button)findViewById(R.id.btn_videoViewDemo1); 
     btn_videoViewDemo2 = (Button)findViewById(R.id.btn_videoViewDemo2); 
     btn_MediaPlayerDemo1 = (Button)findViewById(R.id.btn_MediaPlayerDemo1); 
     btn_MediaPlayerDemo2 = (Button)findViewById(R.id.btn_MediaPlayerDemo2); 

     btn_videoViewDemo1.setOnClickListener(new View.OnClickListener(){ 
      @Override 
      public void onClick(View v) { 
       // TODO Auto-generated method stub 
       Intent Navigation1 = new Intent(MainMenu.this,streamplayer.class); 
       Navigation1.putExtra("video",1); 
       startActivity(Navigation1);    
      } 
     }); 

     btn_videoViewDemo2.setOnClickListener(new View.OnClickListener(){ 
      @Override 
      public void onClick(View v) { 
       // TODO Auto-generated method stub 
       Intent Navigation1 = new Intent(MainMenu.this,streamplayer.class); 
       Navigation1.putExtra("video",2); 
       startActivity(Navigation1); 
      } 
     }); 

     btn_MediaPlayerDemo1.setOnClickListener(new View.OnClickListener(){ 
      @Override 
      public void onClick(View v) { 
       // TODO Auto-generated method stub 
       Intent Navigation1 = new Intent(MainMenu.this,MediaPlayerDemo_Video.class); 
       Navigation1.putExtra("video",1); 
       startActivity(Navigation1);    
      } 
     }); 

     btn_MediaPlayerDemo2.setOnClickListener(new View.OnClickListener(){ 
      @Override 
      public void onClick(View v) { 
       // TODO Auto-generated method stub 
       Intent Navigation1 = new Intent(MainMenu.this,MediaPlayerDemo_Video.class); 
       Navigation1.putExtra("video",2); 
       startActivity(Navigation1);    
      } 
     });  
    } 
} 

streamplayer.java

package com.videostreaming.player; 

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.MediaController; 
import android.widget.Toast; 
import android.widget.VideoView; 

public class streamplayer extends Activity { 
    /** Called when the activity is first created. */ 

    private String path1 = "http://podcast.20min-tv.ch/podcast/20min/199733.mp4"; 
    //private String path2 = "http://podcast.20min-tv.ch/podcast/20min/199752.mp4"; 
    private String path2 = "http://podcast.20min-tv.ch/podcast/20min/199693.mp4"; 
    private String path = ""; 

    //// Method 1 - Default Method 
    private VideoView mVideoView; 

    private Bundle bdlReceivedData = null; 
    private Intent self = null; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     try 
     { 
      setContentView(R.layout.videoview); 
      mVideoView = (VideoView) findViewById(R.id.surface_view); 

      self = this.getIntent(); 
      bdlReceivedData = self.getExtras(); 

      if (bdlReceivedData != null && bdlReceivedData.getInt("video") > 0) 
      { 
       if (bdlReceivedData.getInt("video") == 1) 
       { 
        Toast.makeText(streamplayer.this,"playing Video 1", Toast.LENGTH_SHORT); 
        path = path1; 
       } 
       else if (bdlReceivedData.getInt("video") == 2) 
       { 
        Toast.makeText(streamplayer.this,"playing Video 2", Toast.LENGTH_SHORT); 
        path = path2; 
       } 

       /* 
       * Alternatively,for streaming media you can use 
       * mVideoView.setVideoURI(Uri.parse(URLstring)); 
       */ 

       //mVideoView.setVideoPath(path1); 
       ///ELSE 
       mVideoView.setVideoURI(Uri.parse(path));     
       mVideoView.setMediaController(new MediaController(this)); 
       mVideoView.requestFocus();    
       mVideoView.postInvalidateDelayed(100);   
       mVideoView.start(); 

      } 

     }catch (Exception e) { 
      // TODO: handle exception 
      e.printStackTrace(); 
      Toast.makeText(streamplayer.this,"Error Occured:- " + e.getMessage(),Toast.LENGTH_SHORT).show(); 
     } 
    } 
} 

mediaplayer_2.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <SurfaceView android:id="@+id/surface" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     android:layout_gravity="center"> 
    </SurfaceView> 

</LinearLayout> 

videoview.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"> 

    <VideoView 
     android:id="@+id/surface_view" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     android:layout_gravity="center"/> 

</LinearLayout> 

main.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" > 

<TextView 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"/> 

    <Button 
     android:id="@+id/btn_videoViewDemo1" 
     android:layout_width="fill_parent" 
     android:layout_height="40dip" 
     android:text="VideoView1" 
     android:layout_margin="10dip"> 
    </Button> 

    <Button 
     android:id="@+id/btn_videoViewDemo2" 
     android:layout_width="fill_parent" 
     android:layout_height="40dip" 
     android:text="VideoView2" 
     android:layout_margin="10dip"> 
    </Button> 

    <Button 
     android:id="@+id/btn_MediaPlayerDemo1" 
     android:layout_width="fill_parent" 
     android:layout_height="40dip" 
     android:text="MediaPlayerDemo1" 
     android:layout_margin="10dip"> 
    </Button> 



    <Button 
     android:id="@+id/btn_MediaPlayerDemo2" 
     android:layout_width="fill_parent" 
     android:layout_height="40dip" 
     android:text="MediaPlayerDemo2" 
     android:layout_margin="10dip"> 
    </Button> 


</LinearLayout> 
+8

¿Leyó la pregunta? – pinxue

0

Si la aplicación para Android funciona bien, y el código que está optimitzed, demostrablemente la razón de este retraso es que son La transmisión de datos pesados ​​al servidor y la solicitud HTTP a un servidor tienen un límite de MB para enviar. Cuando eso sucede la clase automáticamente o el programador debe fraccionar la solicitud HTTP a múltiples solicitudes HTTP y, obviamente, es más lento.

1

Si está configurado para la transmisión RTMP desde Android, la mejor solución es MediaCodec + FFmpeg + librtmp. Esto evita cualquier hacky "detectar la unidad NAL dentro del bittest", pero requiere Android 4.3. Patina donde va el disco ...

He desarrollado un open source SDK que demuestra la transmisión RTMP con FFmpeg + librtmp as pre-built shared libraries. El SDK se centra en la transmisión de HLS, pero el soporte de RTMP está presente.

Si quieres ayuda para compilar FFmpeg para Android (con o sin librtmp), check out my guide.

+0

¿funciona sin la cuenta kickflip? ¿Puedo transmitir a cualquier cliente HLS? – 4ntoine

+0

¡Claro! Intente usar un [AVRecorder.java] (https://github.com/Kickflip/kickflip-android-sdk/blob/preview/sdk/src/main/java/io/kickflip/sdk/av/AVRecorder.java) con a [HLSFileMonitor.java] (https://github.com/Kickflip/kickflip-android-sdk/blob/preview/sdk/src/main/java/io/kickflip/sdk/av/HlsFileObserver.java) para supervisar cuándo Los segmentos .ts y .m3u8 están listos para cargarse. [Broadcaster.java] (https://github.com/Kickflip/kickflip-android-sdk/blob/preview/sdk/src/main/java/io/kickflip/sdk/av/Broadcaster.java) es la referencia de Kickflip implementación. – dbro

Cuestiones relacionadas