2012-05-17 95 views
3

我正在通過VideoView在我的Android應用程序中打開IP攝像頭的RTSP流。有一個問題,它有一個很大的延遲超過20秒!儘管通過瀏覽器從普通PC觀看相機不存在這樣的延遲。有什麼想法嗎?Android VideoView RTSP延遲

我的代碼:

 String path="rtsp://192.168.1.20/3gpp"; 
     myVideoView.setVideoURI(Uri.parse(path)); 
     myVideoView.setMediaController(new MediaController(this)); 
     myVideoView.requestFocus(); 
     myVideoView.start(); 
+0

這篇文章可能會有所幫助:http://stackoverflow.com/questions/3937241/reduce-video-buffering – cjpa

回答

2

使用MJPEG流,而不是RTSP。經過大量研究,我發現了一個MJPEG查看器類,可以實時播放實時流(取決於您的網絡連接)。

Here's代碼Android and MJPEG

0

你可以做到這

MjpegSample類

package de.mjpegsample; 

import android.app.Activity; 
import android.os.Bundle; 
import android.view.Menu; 
import android.view.MenuItem; 
import android.view.Window; 
import android.view.WindowManager; 
import de.mjpegsample.MjpegView.MjpegInputStream; 
import de.mjpegsample.MjpegView.MjpegView; 

public class MjpegSample extends Activity { 

private MjpegView mv; 
private static final int MENU_QUIT = 1; 

/* Creates the menu items */ 
public boolean onCreateOptionsMenu(Menu menu) {  
menu.add(0, MENU_QUIT, 0, "Quit"); 
return true; 
} 

/* Handles item selections */ 
public boolean onOptionsItemSelected(MenuItem item) {  
    switch (item.getItemId()) { 
     case MENU_QUIT: 
      finish(); 
      return true;  
     }  
    return false; 
} 

public void onCreate(Bundle icicle) { 
    super.onCreate(icicle); 
    //sample public cam 
    String URL = "http://gamic.dnsalias.net:7001/img/video.mjpeg"; 

    requestWindowFeature(Window.FEATURE_NO_TITLE); 
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); 
    mv = new MjpegView(this); 
    setContentView(mv);   
    mv.setSource(MjpegInputStream.read(URL)); 
    mv.setDisplayMode(MjpegView.SIZE_BEST_FIT); 
    mv.showFps(false); 
} 

public void onPause() { 
    super.onPause(); 
    mv.stopPlayback(); 
} 
} 

MjepgView

import java.io.IOException; 

import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.PorterDuff; 
import android.graphics.PorterDuffXfermode; 
import android.graphics.Rect; 
import android.graphics.Typeface; 
import android.util.AttributeSet; 
import android.view.SurfaceHolder; 
import android.view.SurfaceView; 

public class MjpegView extends SurfaceView implements SurfaceHolder.Callback { 
public final static int POSITION_UPPER_LEFT = 9; 
public final static int POSITION_UPPER_RIGHT = 3; 
public final static int POSITION_LOWER_LEFT = 12; 
public final static int POSITION_LOWER_RIGHT = 6; 

public final static int SIZE_STANDARD = 1; 
public final static int SIZE_BEST_FIT = 4; 
public final static int SIZE_FULLSCREEN = 8; 

private MjpegViewThread thread; 
private MjpegInputStream mIn = null;  
private boolean showFps = false; 
private boolean mRun = false; 
private boolean surfaceDone = false;  
private Paint overlayPaint; 
private int overlayTextColor; 
private int overlayBackgroundColor; 
private int ovlPos; 
private int dispWidth; 
private int dispHeight; 
private int displayMode; 

public class MjpegViewThread extends Thread { 
    private SurfaceHolder mSurfaceHolder; 
    private int frameCounter = 0; 
    private long start; 
    private Bitmap ovl; 

    public MjpegViewThread(SurfaceHolder surfaceHolder, Context context) { mSurfaceHolder = surfaceHolder; } 

    private Rect destRect(int bmw, int bmh) { 
     int tempx; 
     int tempy; 
     if (displayMode == MjpegView.SIZE_STANDARD) { 
      tempx = (dispWidth/2) - (bmw/2); 
      tempy = (dispHeight/2) - (bmh/2); 
      return new Rect(tempx, tempy, bmw + tempx, bmh + tempy); 
     } 
     if (displayMode == MjpegView.SIZE_BEST_FIT) { 
      float bmasp = (float) bmw/(float) bmh; 
      bmw = dispWidth; 
      bmh = (int) (dispWidth/bmasp); 
      if (bmh > dispHeight) { 
       bmh = dispHeight; 
       bmw = (int) (dispHeight * bmasp); 
      } 
      tempx = (dispWidth/2) - (bmw/2); 
      tempy = (dispHeight/2) - (bmh/2); 
      return new Rect(tempx, tempy, bmw + tempx, bmh + tempy); 
     } 
     if (displayMode == MjpegView.SIZE_FULLSCREEN) return new Rect(0, 0, dispWidth, dispHeight); 
     return null; 
    } 

    public void setSurfaceSize(int width, int height) { 
     synchronized(mSurfaceHolder) { 
      dispWidth = width; 
      dispHeight = height; 
     } 
    } 

    private Bitmap makeFpsOverlay(Paint p, String text) { 
     Rect b = new Rect(); 
     p.getTextBounds(text, 0, text.length(), b); 
     int bwidth = b.width()+2; 
     int bheight = b.height()+2; 
     Bitmap bm = Bitmap.createBitmap(bwidth, bheight, Bitmap.Config.ARGB_8888); 
     Canvas c = new Canvas(bm); 
     p.setColor(overlayBackgroundColor); 
     c.drawRect(0, 0, bwidth, bheight, p); 
     p.setColor(overlayTextColor); 
     c.drawText(text, -b.left+1, (bheight/2)-((p.ascent()+p.descent())/2)+1, p); 
     return bm;   
    } 

    public void run() { 
     start = System.currentTimeMillis(); 
     PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.DST_OVER); 
     Bitmap bm; 
     int width; 
     int height; 
     Rect destRect; 
     Canvas c = null; 
     Paint p = new Paint(); 
     String fps = ""; 
     while (mRun) { 
      if(surfaceDone) { 
       try { 
        c = mSurfaceHolder.lockCanvas(); 
        synchronized (mSurfaceHolder) { 
         try { 
          bm = mIn.readMjpegFrame(); 
          destRect = destRect(bm.getWidth(),bm.getHeight()); 
          c.drawColor(Color.BLACK); 
          c.drawBitmap(bm, null, destRect, p); 
          if(showFps) { 
           p.setXfermode(mode); 
           if(ovl != null) { 
            height = ((ovlPos & 1) == 1) ? destRect.top : destRect.bottom-ovl.getHeight(); 
            width = ((ovlPos & 8) == 8) ? destRect.left : destRect.right -ovl.getWidth(); 
            c.drawBitmap(ovl, width, height, null); 
           } 
           p.setXfermode(null); 
           frameCounter++; 
           if((System.currentTimeMillis() - start) >= 1000) { 
            fps = String.valueOf(frameCounter)+"fps"; 
            frameCounter = 0; 
            start = System.currentTimeMillis(); 
            ovl = makeFpsOverlay(overlayPaint, fps); 
           } 
          } 
         } catch (IOException e) {} 
        } 
       } finally { if (c != null) mSurfaceHolder.unlockCanvasAndPost(c); } 
      } 
     } 
    } 
} 

private void init(Context context) { 
    SurfaceHolder holder = getHolder(); 
    holder.addCallback(this); 
    thread = new MjpegViewThread(holder, context); 
    setFocusable(true); 
    overlayPaint = new Paint(); 
    overlayPaint.setTextAlign(Paint.Align.LEFT); 
    overlayPaint.setTextSize(12); 
    overlayPaint.setTypeface(Typeface.DEFAULT); 
    overlayTextColor = Color.WHITE; 
    overlayBackgroundColor = Color.BLACK; 
    ovlPos = MjpegView.POSITION_LOWER_RIGHT; 
    displayMode = MjpegView.SIZE_STANDARD; 
    dispWidth = getWidth(); 
    dispHeight = getHeight(); 
} 

public void startPlayback() { 
    if(mIn != null) { 
     mRun = true; 
     thread.start();   
    } 
} 

public void stopPlayback() { 
    mRun = false; 
    boolean retry = true; 
    while(retry) { 
     try { 
      thread.join(); 
      retry = false; 
     } catch (InterruptedException e) {} 
    } 
} 

public MjpegView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } 
public void surfaceChanged(SurfaceHolder holder, int f, int w, int h) { thread.setSurfaceSize(w, h); } 

public void surfaceDestroyed(SurfaceHolder holder) { 
    surfaceDone = false; 
    stopPlayback(); 
} 

public MjpegView(Context context) { 
    super(context); 
    init(context); 
    }  
public void surfaceCreated(SurfaceHolder holder) { 
    surfaceDone = true; 
    } 
public void showFps(boolean b) { 
    showFps = b; 
    } 
public void setSource(MjpegInputStream source) { 
    mIn = source; 
    startPlayback(); 
    } 
public void setOverlayPaint(Paint p) { 
    overlayPaint = p; 
    } 
public void setOverlayTextColor(int c) { 
    overlayTextColor = c; 
    } 
public void setOverlayBackgroundColor(int c) { 
    overlayBackgroundColor = c; 
    } 
public void setOverlayPosition(int p) { 
    ovlPos = p; 
    } 
public void setDisplayMode(int s) { 
    displayMode = s; 
    } 
} 

MjpegInputStream

以下
package de.mjpegsample.MjpegView; 

import java.io.BufferedInputStream; 
import java.io.ByteArrayInputStream; 
import java.io.DataInputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.net.URI; 
import java.util.Properties; 

import org.apache.http.HttpResponse; 
import org.apache.http.client.ClientProtocolException; 
import org.apache.http.client.methods.HttpGet; 
import org.apache.http.impl.client.DefaultHttpClient; 

import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 

public class MjpegInputStream extends DataInputStream { 
private final byte[] SOI_MARKER = { (byte) 0xFF, (byte) 0xD8 }; 
private final byte[] EOF_MARKER = { (byte) 0xFF, (byte) 0xD9 }; 
private final String CONTENT_LENGTH = "Content-Length"; 
private final static int HEADER_MAX_LENGTH = 100; 
private final static int FRAME_MAX_LENGTH = 40000 + HEADER_MAX_LENGTH; 
private int mContentLength = -1; 

public static MjpegInputStream read(String url) { 
    HttpResponse res; 
    DefaultHttpClient httpclient = new DefaultHttpClient();  
    try { 
     res = httpclient.execute(new HttpGet(URI.create(url))); 
     return new MjpegInputStream(res.getEntity().getContent());    
    } catch (ClientProtocolException e) { 
    } catch (IOException e) {} 
    return null; 
} 

public MjpegInputStream(InputStream in) { super(new BufferedInputStream(in, FRAME_MAX_LENGTH)); } 

private int getEndOfSeqeunce(DataInputStream in, byte[] sequence) throws IOException { 
    int seqIndex = 0; 
    byte c; 
    for(int i=0; i < FRAME_MAX_LENGTH; i++) { 
     c = (byte) in.readUnsignedByte(); 
     if(c == sequence[seqIndex]) { 
      seqIndex++; 
      if(seqIndex == sequence.length) return i + 1; 
     } else seqIndex = 0; 
    } 
    return -1; 
} 

private int getStartOfSequence(DataInputStream in, byte[] sequence) throws IOException { 
    int end = getEndOfSeqeunce(in, sequence); 
    return (end < 0) ? (-1) : (end - sequence.length); 
} 

private int parseContentLength(byte[] headerBytes) throws IOException, NumberFormatException { 
    ByteArrayInputStream headerIn = new ByteArrayInputStream(headerBytes); 
    Properties props = new Properties(); 
    props.load(headerIn); 
    return Integer.parseInt(props.getProperty(CONTENT_LENGTH)); 
} 

public Bitmap readMjpegFrame() throws IOException { 
    mark(FRAME_MAX_LENGTH); 
    int headerLen = getStartOfSequence(this, SOI_MARKER); 
    reset(); 
    byte[] header = new byte[headerLen]; 
    readFully(header); 
    try { 
     mContentLength = parseContentLength(header); 
    } catch (NumberFormatException nfe) { 
     mContentLength = getEndOfSeqeunce(this, EOF_MARKER); 
    } 
    reset(); 
    byte[] frameData = new byte[mContentLength]; 
    skipBytes(headerLen); 
    readFully(frameData); 
    return BitmapFactory.decodeStream(new ByteArrayInputStream(frameData)); 
} 
}