2011-07-14 30 views
0

我正在開發一個應用程序,發送一個JPEG圖像(MJPEG流)流到遠程PC。我在更改相機參數中的預覽幀速率時遇到問題。似乎不管我設定的速度如何,相機只給了我一個15幀的幀。起初我認爲這是由於圖像壓縮,然後傳輸數據。但是我創建了一個調試實例,用於存儲第一個壓縮的JPEG圖像,並在每次調用onPreviewFrame函數時發送該圖像。這導致了一個可靠的15fps,但我把它設置爲30fps。任何人有任何想法,爲什麼fps如此不一致?當我將它設置爲壓縮每個預覽幀並通過無線網絡發送時,我可以獲得5-40 FPS的速率,並且它會跳到所有地方。摩托羅拉Atrix不一致的預覽幀

下面是我爲我的預覽代碼(設置相機在全屏幕)

public class Preview extends SurfaceView implements PreviewCallback, SurfaceHolder.Callback { 
SurfaceHolder mHolder; 
Camera mCamera; 
DatagramSocket udpSocket = null; 
final int PORT = 1235; 
final String IPAddress = "192.168.1.101"; 
int packetSize = 1024; // Specify max size of each UDP packet 
int WIDTH = 640; 
int HEIGHT = 480; 
int FPS = 30;  
int quality = 70; 
/** 
* Initialize the Camera Preview Holder and create a udpSocket. 
* @param context 
*/ 
Preview(Context context) { 
    super(context); 
    mHolder = getHolder(); 
    mHolder.addCallback(this); 
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
    try { 
     udpSocket = new DatagramSocket(); 
    } catch (SocketException e) { 
     Log.e(tag, "Error creating UDP Socket!"); 
    } 
} 
public void surfaceCreated(SurfaceHolder holder) { 
    mCamera = Camera.open(); 
    try { 
     mCamera.setPreviewDisplay(holder); 
    } catch (IOException exception) { 
     mCamera.release(); 
     mCamera = null; 
     Log.e(tag, "Error settign Camera Preview Holder!"); 
    } 
} 
public void surfaceDestroyed(SurfaceHolder holder) { 
    mCamera.setPreviewCallback(null); 
    mCamera.stopPreview(); 
    udpSocket.close(); 
    mCamera.release(); 
    udpSocket = null; 
    mCamera = null; 
} 
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
    Camera.Parameters parameters = mCamera.getParameters(); 
    parameters.setPreviewSize(WIDTH, HEIGHT); 
    parameters.setPreviewFrameRate(FPS); 
    parameters.setRotation(90); 

    mCamera.setParameters(parameters); 
    mCamera.setPreviewCallback(this); 
    mCamera.startPreview(); 
} 
/** Compresses the preview framer (data) into a JPEG image and send to a host at 
* the specified IPAddress and Port number for playback. Only sends frame if sendFrame 
* is true. 
* (non-Javadoc) 
* @see android.hardware.Camera.PreviewCallback#onPreviewFrame(byte[], android.hardware.Camera) 
* @see android.hardware.Camera 
*/ 
public void onPreviewFrame(byte[] data, Camera camera) { 
    final YuvImage imgPreview = new YuvImage(data, ImageFormat.NV21, WIDTH, HEIGHT, null); 
    byte[] buffer; 
    ByteArrayOutputStream jpegOutStream = new ByteArrayOutputStream(); 

    int offset = 0; 
    int TotalLength, lengthLeft; 
    DatagramPacket dgpout; 
    // Compress image into JPEG 
    imgPreview.compressToJpeg(new Rect(0, 0, imgPreview.getWidth(), imgPreview.getHeight()), quality, jpegOutStream); 
    buffer = jpegOutStream.toByteArray(); 
    TotalLength = lengthLeft = buffer.length; 
    // Send frame out. Split into packets of desired length. 
    try { 
     while(lengthLeft>packetSize){ 
      dgpout= new DatagramPacket(buffer, offset, packetSize); 
      offset+=packetSize; 
      lengthLeft-=packetSize; 
      dgpout.setAddress(InetAddress.getByName(IPAddress)); 
      dgpout.setPort(PORT); 
      udpSocket.send(dgpout); 
     } 
     if(lengthLeft>0){ 
      dgpout= new DatagramPacket(buffer,offset,lengthLeft); 
      offset+=lengthLeft; 
      lengthLeft-=lengthLeft; 
      dgpout.setAddress(InetAddress.getByName(IPAddress)); 
      dgpout.setPort(PORT); 
      udpSocket.send(dgpout); 
     } 
     Log.i(tag, "Sent Successfully: frame size="+TotalLength +"Buffer Size: "+udpSocket.getSendBufferSize()); 
    } catch (UnknownHostException e1) { 
     Log.e(tag , "UnknownHostException. Sending failed."); 
    } catch (IOException e) { 
     Log.e(tag , "IOException. Sending failed."); 
    } 
} 

}

這裏是我的調試樣品僅在發送相同的JPEG和超過

if(sendFrame){ 
     sendFrame = false; 
     final YuvImage imgPreview = new YuvImage(data, ImageFormat.NV21, WIDTH, HEIGHT, null); 

     fixImage = data; 
       byte[] buffer; 
       ByteArrayOutputStream jpegOutStream = new ByteArrayOutputStream(); 

       int offset = 0; 
       int TotalLength, lengthLeft; 
       DatagramPacket dgpout; 
       // Compress image into JPEG 
       imgPreview.compressToJpeg(new Rect(0, 0, imgPreview.getWidth(), imgPreview.getHeight()), quality, jpegOutStream); 
       buffer = jpegOutStream.toByteArray(); 

       fixJPEG = buffer; 
       fixTotalLength = buffer.length; 

    } 
    int lengthLeft = 0; 
    int offset = 0; 
    DatagramPacket dgpout; 
    if(fixImage==null || fixJPEG==null) 
     return; 
    /* Compress Optional */ 
    if(true){ 
     final YuvImage imgPreview = new YuvImage(fixImage, ImageFormat.NV21, WIDTH, HEIGHT, null); 
     ByteArrayOutputStream jpegOutStream = new ByteArrayOutputStream(); 
     imgPreview.compressToJpeg(new Rect(0, 0, imgPreview.getWidth(), imgPreview.getHeight()), quality, jpegOutStream); 
     fixJPEG = jpegOutStream.toByteArray(); 
    } 
    fixTotalLength = lengthLeft = fixJPEG.length; 
    // Send frame out. Split into packets of desired length. 
    try { 
     while(lengthLeft>packetSize){ 
      dgpout= new DatagramPacket(fixJPEG, offset, packetSize); 
      offset+=packetSize; 
      lengthLeft-=packetSize; 
      dgpout.setAddress(InetAddress.getByName(IPAddress)); 
      dgpout.setPort(PORT); 
      udpSocket.send(dgpout); 
     } 
     if(lengthLeft>0){ 
     dgpout= new DatagramPacket(fixJPEG,offset,lengthLeft); 
      offset+=lengthLeft; 
      lengthLeft-=lengthLeft; 
      dgpout.setAddress(InetAddress.getByName(IPAddress)); 
      dgpout.setPort(PORT); 
      udpSocket.send(dgpout); 
     } 
     Log.i(tag, "Sent Successfully: frame size="+fixTotalLength +"Buffer Size: "+udpSocket.getSendBufferSize()); 
    } catch (UnknownHostException e1) { 
     Log.e(tag , "UnknownHostException. Sending failed."); 
    } catch (IOException e) { 
     Log.e(tag , "IOException. Sending failed."); 
    } 

有沒有人有提高效率的任何想法?這是否發生在所有設備上?我正在運行Android 2.2。任何想法都表示讚賞。

*編輯增加了整個預覽類

+0

你還可以發佈你用來設置相機的代碼嗎? – mportuesisf

+0

@mportuesisf我發佈了包含請求信息的整個預覽類。感謝您的迴應。 –

回答

2

它很可能的是Atrix的(合法)忽略你的要求更改預覽幀速率。

在你surfaceChanged回調,嘗試調用以下並在調試檢查值:

List<Integer> rates = parameters.getSupportedPreviewFrameRates(); 

Android的文件說:

返回支持預覽幀速率的列表。如果預覽幀 不支持速率設置,則爲空。

此外,對於setPreviewFrameRate()的文件說:

這是目標幀速率。實際幀速率取決於驅動程序 。

所以,它可能是Atrix不支持15fps以外的任何其他預覽。

在任何情況下,使用預覽幀速率的正確方法是首先調用getSupportedPreviewFrameRates()。如果它返回一個非空結果,那麼在列表中找到最接近的數字並將其傳遞給setPreviewFrameRate()。否則,你將不得不忍受設備支持的任何速率。

+0

謝謝你的回覆。你的回答確實爲我提供了一些啓示。目標幀速率似乎與實際幀速率大不相同。從現在開始,我將使用正確的方式來設置參數。再次感謝! –